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