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 static const float kBlue[] = {0.0f, 0.0f, 1.0f, 1.0f};
176 static const float kGreen[] = {0.0f, 1.0f, 0.0f, 1.0f};
177 static const float kRed[] = {1.0f, 0.0f, 0.0f, 1.0f};
178
179 // Different drivers seem to behave differently with respect to resulting
180 // values. These might be due to different MSAA sample counts causing
181 // different samples to hit. Other option is driver bugs. Just test that
182 // disabling multisample causes a difference.
183 std::unique_ptr<uint8_t[]> results[3];
184 const GLint kResultSize = kWidth * kHeight * 4;
185 for (int pass = 0; pass < 3; pass++)
186 {
187 prepareForDraw();
188 // Green: from top right to bottom left.
189 glUniform4fv(mColorLoc, 1, kGreen);
190 glDrawArrays(GL_TRIANGLES, 0, 3);
191
192 // Blue: from top left to bottom right.
193 glUniform4fv(mColorLoc, 1, kBlue);
194 glDrawArrays(GL_TRIANGLES, 3, 3);
195
196 // Red, with and without MSAA: from bottom left to top right.
197 if (pass == 1)
198 {
199 glDisable(GL_MULTISAMPLE_EXT);
200 }
201 glUniform4fv(mColorLoc, 1, kRed);
202 glDrawArrays(GL_TRIANGLES, 6, 3);
203 if (pass == 1)
204 {
205 glEnable(GL_MULTISAMPLE_EXT);
206 }
207 prepareForVerify();
208 results[pass].reset(new uint8_t[kResultSize]);
209 memset(results[pass].get(), 123u, kResultSize);
210 glReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, results[pass].get());
211
212 cleanup();
213 }
214 EXPECT_NE(0, memcmp(results[0].get(), results[1].get(), kResultSize));
215 // Verify that rendering is deterministic, so that the pass above does not
216 // come from non-deterministic rendering.
217 EXPECT_EQ(0, memcmp(results[0].get(), results[2].get(), kResultSize));
218 }
219
220 // Test that enabling GL_SAMPLE_ALPHA_TO_ONE_EXT affects rendering.
TEST_P(EXTMultisampleCompatibilityTest,DrawAlphaOneAndResolve)221 TEST_P(EXTMultisampleCompatibilityTest, DrawAlphaOneAndResolve)
222 {
223 if (!isApplicable())
224 return;
225
226 // SAMPLE_ALPHA_TO_ONE is specified to transform alpha values of
227 // covered samples to 1.0. In order to detect it, we use non-1.0
228 // alpha.
229 static const float kBlue[] = {0.0f, 0.0f, 1.0f, 0.5f};
230 static const float kGreen[] = {0.0f, 1.0f, 0.0f, 0.5f};
231 static const float kRed[] = {1.0f, 0.0f, 0.0f, 0.5f};
232
233 // Different drivers seem to behave differently with respect to resulting
234 // alpha value. These might be due to different MSAA sample counts causing
235 // different samples to hit. Other option is driver bugs. Testing exact or
236 // even approximate sample values is not that easy. Thus, just test
237 // representative positions which have fractional pixels, inspecting that
238 // normal rendering is different to SAMPLE_ALPHA_TO_ONE rendering.
239 std::unique_ptr<uint8_t[]> results[3];
240 const GLint kResultSize = kWidth * kHeight * 4;
241
242 for (int pass = 0; pass < 3; ++pass)
243 {
244 prepareForDraw();
245 if (pass == 1)
246 {
247 glEnable(GL_SAMPLE_ALPHA_TO_ONE_EXT);
248 }
249 glEnable(GL_MULTISAMPLE_EXT);
250 glUniform4fv(mColorLoc, 1, kGreen);
251 glDrawArrays(GL_TRIANGLES, 0, 3);
252
253 glUniform4fv(mColorLoc, 1, kBlue);
254 glDrawArrays(GL_TRIANGLES, 3, 3);
255
256 glDisable(GL_MULTISAMPLE_EXT);
257 glUniform4fv(mColorLoc, 1, kRed);
258 glDrawArrays(GL_TRIANGLES, 6, 3);
259
260 prepareForVerify();
261 results[pass].reset(new uint8_t[kResultSize]);
262 memset(results[pass].get(), 123u, kResultSize);
263 glReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, results[pass].get());
264 if (pass == 1)
265 {
266 glDisable(GL_SAMPLE_ALPHA_TO_ONE_EXT);
267 }
268
269 cleanup();
270 }
271 EXPECT_NE(0, memcmp(results[0].get(), results[1].get(), kResultSize));
272 // Verify that rendering is deterministic, so that the pass above does not
273 // come from non-deterministic rendering.
274 EXPECT_EQ(0, memcmp(results[0].get(), results[2].get(), kResultSize));
275 }
276
277 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(EXTMultisampleCompatibilityTest);
278
279 class MultisampleCompatibilityTest : public ANGLETest
280 {
281
282 protected:
MultisampleCompatibilityTest()283 MultisampleCompatibilityTest()
284 {
285 setWindowWidth(64);
286 setWindowHeight(64);
287 setConfigRedBits(8);
288 setConfigBlueBits(8);
289 setConfigAlphaBits(8);
290 }
291
prepareForDraw(GLsizei numSamples)292 void prepareForDraw(GLsizei numSamples)
293 {
294 // Create a sample buffer.
295 glGenRenderbuffers(1, &mSampleRB);
296 glBindRenderbuffer(GL_RENDERBUFFER, mSampleRB);
297 glRenderbufferStorageMultisampleANGLE(GL_RENDERBUFFER, numSamples, GL_RGBA8, kWidth,
298 kHeight);
299 GLint param = 0;
300 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, ¶m);
301 EXPECT_GE(param, numSamples);
302 glGenFramebuffers(1, &mSampleFBO);
303 glBindFramebuffer(GL_FRAMEBUFFER, mSampleFBO);
304 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, mSampleRB);
305 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
306 glBindFramebuffer(GL_FRAMEBUFFER, 0);
307 // Create another FBO to resolve the multisample buffer into.
308 glGenTextures(1, &mResolveTex);
309 glBindTexture(GL_TEXTURE_2D, mResolveTex);
310 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
311 nullptr);
312 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
313 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
314 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
315 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
316 glGenFramebuffers(1, &mResolveFBO);
317 glBindFramebuffer(GL_FRAMEBUFFER, mResolveFBO);
318 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mResolveTex, 0);
319 EXPECT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
320 glViewport(0, 0, kWidth, kHeight);
321 glBindFramebuffer(GL_FRAMEBUFFER, mSampleFBO);
322 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
323 glClear(GL_COLOR_BUFFER_BIT);
324 ASSERT_GL_NO_ERROR();
325 }
326
prepareForVerify()327 void prepareForVerify()
328 {
329 // Resolve.
330 glBindFramebuffer(GL_READ_FRAMEBUFFER, mSampleFBO);
331 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mResolveFBO);
332 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
333 glClear(GL_COLOR_BUFFER_BIT);
334 glBlitFramebufferANGLE(0, 0, kWidth, kHeight, 0, 0, kWidth, kHeight, GL_COLOR_BUFFER_BIT,
335 GL_NEAREST);
336 glBindFramebuffer(GL_READ_FRAMEBUFFER, mResolveFBO);
337
338 ASSERT_GL_NO_ERROR();
339 }
340
cleanup()341 void cleanup()
342 {
343 glBindFramebuffer(GL_FRAMEBUFFER, 0);
344 glDeleteFramebuffers(1, &mResolveFBO);
345 glDeleteFramebuffers(1, &mSampleFBO);
346 glDeleteTextures(1, &mResolveTex);
347 glDeleteRenderbuffers(1, &mSampleRB);
348
349 ASSERT_GL_NO_ERROR();
350 }
351
isApplicable() const352 bool isApplicable() const
353 {
354 return IsGLExtensionEnabled("GL_ANGLE_framebuffer_multisample") &&
355 IsGLExtensionEnabled("GL_OES_rgb8_rgba8");
356 }
357
358 GLuint mSampleFBO;
359 GLuint mResolveFBO;
360 GLuint mSampleRB;
361 GLuint mResolveTex;
362 };
363
364 // Test that enabling GL_SAMPLE_COVERAGE affects rendering.
TEST_P(MultisampleCompatibilityTest,DrawCoverageAndResolve)365 TEST_P(MultisampleCompatibilityTest, DrawCoverageAndResolve)
366 {
367 if (!isApplicable())
368 return;
369
370 // TODO: Figure out why this fails on Android.
371 ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGLES());
372
373 ANGLE_GL_PROGRAM(drawRed, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
374
375 GLsizei maxSamples = 0;
376 glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
377 int iterationCount = maxSamples + 1;
378 for (int samples = 1; samples < iterationCount; samples++)
379 {
380 prepareForDraw(samples);
381 glEnable(GL_SAMPLE_COVERAGE);
382 glSampleCoverage(1.0, false);
383 drawQuad(drawRed.get(), essl1_shaders::PositionAttrib(), 0.5f);
384
385 prepareForVerify();
386 GLsizei pixelCount = kWidth * kHeight;
387 std::vector<GLColor> actual(pixelCount, GLColor::black);
388 glReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, actual.data());
389 glDisable(GL_SAMPLE_COVERAGE);
390 cleanup();
391
392 std::vector<GLColor> expected(pixelCount, GLColor::red);
393 EXPECT_EQ(expected, actual);
394 }
395 }
396
397 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(MultisampleCompatibilityTest);
398