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 
7 #include "test_utils/ANGLETest.h"
8 
9 #include "random_utils.h"
10 #include "Vector.h"
11 
12 using namespace angle;
13 
14 namespace
15 {
16 
RandomVec4(int seed,float minValue,float maxValue)17 Vector4 RandomVec4(int seed, float minValue, float maxValue)
18 {
19     RNG rng(seed);
20     srand(seed);
21     return Vector4(
22         rng.randomFloatBetween(minValue, maxValue), rng.randomFloatBetween(minValue, maxValue),
23         rng.randomFloatBetween(minValue, maxValue), rng.randomFloatBetween(minValue, maxValue));
24 }
25 
Vec4ToColor(const Vector4 & vec)26 GLColor Vec4ToColor(const Vector4 &vec)
27 {
28     GLColor color;
29     color.R = static_cast<uint8_t>(vec.x * 255.0f);
30     color.G = static_cast<uint8_t>(vec.y * 255.0f);
31     color.B = static_cast<uint8_t>(vec.z * 255.0f);
32     color.A = static_cast<uint8_t>(vec.w * 255.0f);
33     return color;
34 };
35 
36 class ClearTestBase : public ANGLETest
37 {
38   protected:
ClearTestBase()39     ClearTestBase() : mProgram(0)
40     {
41         setWindowWidth(128);
42         setWindowHeight(128);
43         setConfigRedBits(8);
44         setConfigGreenBits(8);
45         setConfigBlueBits(8);
46         setConfigAlphaBits(8);
47         setConfigDepthBits(24);
48     }
49 
SetUp()50     void SetUp() override
51     {
52         ANGLETest::SetUp();
53 
54         mFBOs.resize(2, 0);
55         glGenFramebuffers(2, mFBOs.data());
56 
57         ASSERT_GL_NO_ERROR();
58     }
59 
TearDown()60     void TearDown() override
61     {
62         glDeleteProgram(mProgram);
63 
64         if (!mFBOs.empty())
65         {
66             glDeleteFramebuffers(static_cast<GLsizei>(mFBOs.size()), mFBOs.data());
67         }
68 
69         if (!mTextures.empty())
70         {
71             glDeleteTextures(static_cast<GLsizei>(mTextures.size()), mTextures.data());
72         }
73 
74         ANGLETest::TearDown();
75     }
76 
setupDefaultProgram()77     void setupDefaultProgram()
78     {
79         const std::string vertexShaderSource = SHADER_SOURCE
80         (
81             precision highp float;
82             attribute vec4 position;
83 
84             void main()
85             {
86                 gl_Position = position;
87             }
88         );
89 
90         const std::string fragmentShaderSource = SHADER_SOURCE
91         (
92             precision highp float;
93 
94             void main()
95             {
96                 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
97             }
98         );
99 
100         mProgram = CompileProgram(vertexShaderSource, fragmentShaderSource);
101         ASSERT_NE(0u, mProgram);
102     }
103 
104     GLuint mProgram;
105     std::vector<GLuint> mFBOs;
106     std::vector<GLuint> mTextures;
107 };
108 
109 class ClearTest : public ClearTestBase {};
110 class ClearTestES3 : public ClearTestBase {};
111 
112 // Test clearing the default framebuffer
TEST_P(ClearTest,DefaultFramebuffer)113 TEST_P(ClearTest, DefaultFramebuffer)
114 {
115     glClearColor(0.25f, 0.5f, 0.5f, 0.5f);
116     glClear(GL_COLOR_BUFFER_BIT);
117     EXPECT_PIXEL_NEAR(0, 0, 64, 128, 128, 128, 1.0);
118 }
119 
120 // Test clearing a RGBA8 Framebuffer
TEST_P(ClearTest,RGBA8Framebuffer)121 TEST_P(ClearTest, RGBA8Framebuffer)
122 {
123     glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]);
124 
125     GLuint texture;
126     glGenTextures(1, &texture);
127 
128     glBindTexture(GL_TEXTURE_2D, texture);
129     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
130                  GL_UNSIGNED_BYTE, nullptr);
131     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
132 
133     glClearColor(0.5f, 0.5f, 0.5f, 0.5f);
134     glClear(GL_COLOR_BUFFER_BIT);
135 
136     EXPECT_PIXEL_NEAR(0, 0, 128, 128, 128, 128, 1.0);
137 }
138 
TEST_P(ClearTest,ClearIssue)139 TEST_P(ClearTest, ClearIssue)
140 {
141     // TODO(geofflang): Figure out why this is broken on Intel OpenGL
142     if (IsIntel() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
143     {
144         std::cout << "Test skipped on Intel OpenGL." << std::endl;
145         return;
146     }
147 
148     glEnable(GL_DEPTH_TEST);
149     glDepthFunc(GL_LEQUAL);
150 
151     glClearColor(0.0, 1.0, 0.0, 1.0);
152     glClearDepthf(0.0);
153     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
154 
155     EXPECT_GL_NO_ERROR();
156 
157     glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]);
158 
159     GLuint rbo;
160     glGenRenderbuffers(1, &rbo);
161     glBindRenderbuffer(GL_RENDERBUFFER, rbo);
162     glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB565, 16, 16);
163 
164     EXPECT_GL_NO_ERROR();
165 
166     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
167 
168     EXPECT_GL_NO_ERROR();
169 
170     glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
171     glClearDepthf(1.0f);
172     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
173 
174     EXPECT_GL_NO_ERROR();
175 
176     glBindFramebuffer(GL_FRAMEBUFFER, 0);
177     glBindBuffer(GL_ARRAY_BUFFER, 0);
178 
179     setupDefaultProgram();
180     drawQuad(mProgram, "position", 0.5f);
181 
182     EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
183 }
184 
185 // Requires ES3
186 // This tests a bug where in a masked clear when calling "ClearBuffer", we would
187 // mistakenly clear every channel (including the masked-out ones)
TEST_P(ClearTestES3,MaskedClearBufferBug)188 TEST_P(ClearTestES3, MaskedClearBufferBug)
189 {
190     unsigned char pixelData[] = { 255, 255, 255, 255 };
191 
192     glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]);
193 
194     GLuint textures[2];
195     glGenTextures(2, &textures[0]);
196 
197     glBindTexture(GL_TEXTURE_2D, textures[0]);
198     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixelData);
199     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0], 0);
200 
201     glBindTexture(GL_TEXTURE_2D, textures[1]);
202     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixelData);
203     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, textures[1], 0);
204 
205     ASSERT_GL_NO_ERROR();
206     EXPECT_PIXEL_EQ(0, 0, 255, 255, 255, 255);
207 
208     float clearValue[] = { 0, 0.5f, 0.5f, 1.0f };
209     GLenum drawBuffers[] = { GL_NONE, GL_COLOR_ATTACHMENT1 };
210     glDrawBuffers(2, drawBuffers);
211     glColorMask(GL_TRUE, GL_TRUE, GL_FALSE, GL_TRUE);
212     glClearBufferfv(GL_COLOR, 1, clearValue);
213 
214     ASSERT_GL_NO_ERROR();
215     EXPECT_PIXEL_EQ(0, 0, 255, 255, 255, 255);
216 
217     glReadBuffer(GL_COLOR_ATTACHMENT1);
218     ASSERT_GL_NO_ERROR();
219 
220     EXPECT_PIXEL_NEAR(0, 0, 0, 127, 255, 255, 1);
221 
222     glDeleteTextures(2, textures);
223 }
224 
TEST_P(ClearTestES3,BadFBOSerialBug)225 TEST_P(ClearTestES3, BadFBOSerialBug)
226 {
227     // First make a simple framebuffer, and clear it to green
228     glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]);
229 
230     GLuint textures[2];
231     glGenTextures(2, &textures[0]);
232 
233     glBindTexture(GL_TEXTURE_2D, textures[0]);
234     glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, getWindowWidth(), getWindowHeight());
235     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0], 0);
236 
237     GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0 };
238     glDrawBuffers(1, drawBuffers);
239 
240     float clearValues1[] = { 0.0f, 1.0f, 0.0f, 1.0f };
241     glClearBufferfv(GL_COLOR, 0, clearValues1);
242 
243     ASSERT_GL_NO_ERROR();
244     EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
245 
246     // Next make a second framebuffer, and draw it to red
247     // (Triggers bad applied render target serial)
248     GLuint fbo2;
249     glGenFramebuffers(1, &fbo2);
250     ASSERT_GL_NO_ERROR();
251 
252     glBindFramebuffer(GL_FRAMEBUFFER, fbo2);
253 
254     glBindTexture(GL_TEXTURE_2D, textures[1]);
255     glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, getWindowWidth(), getWindowHeight());
256     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[1], 0);
257 
258     glDrawBuffers(1, drawBuffers);
259 
260     setupDefaultProgram();
261     drawQuad(mProgram, "position", 0.5f);
262 
263     ASSERT_GL_NO_ERROR();
264     EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
265 
266     // Check that the first framebuffer is still green.
267     glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]);
268     EXPECT_PIXEL_EQ(0, 0, 0, 255, 0, 255);
269 
270     glDeleteTextures(2, textures);
271     glDeleteFramebuffers(1, &fbo2);
272 }
273 
274 // Test that SRGB framebuffers clear to the linearized clear color
TEST_P(ClearTestES3,SRGBClear)275 TEST_P(ClearTestES3, SRGBClear)
276 {
277     // TODO(jmadill): figure out why this fails
278     if (IsIntel() && GetParam() == ES3_OPENGL())
279     {
280         std::cout << "Test skipped on Intel due to failures." << std::endl;
281         return;
282     }
283 
284     // First make a simple framebuffer, and clear it
285     glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]);
286 
287     GLuint texture;
288     glGenTextures(1, &texture);
289 
290     glBindTexture(GL_TEXTURE_2D, texture);
291     glTexStorage2D(GL_TEXTURE_2D, 1, GL_SRGB8_ALPHA8, getWindowWidth(), getWindowHeight());
292     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
293 
294     glClearColor(0.5f, 0.5f, 0.5f, 0.5f);
295     glClear(GL_COLOR_BUFFER_BIT);
296 
297     EXPECT_PIXEL_NEAR(0, 0, 188, 188, 188, 128, 1.0);
298 }
299 
300 // Test that framebuffers with mixed SRGB/Linear attachments clear to the correct color for each
301 // attachment
TEST_P(ClearTestES3,MixedSRGBClear)302 TEST_P(ClearTestES3, MixedSRGBClear)
303 {
304     // TODO(cwallez) figure out why it is broken on Intel on Mac
305 #if defined(ANGLE_PLATFORM_APPLE)
306     if (IsIntel() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
307     {
308         std::cout << "Test skipped on Intel on Mac." << std::endl;
309         return;
310     }
311 #endif
312 
313     // TODO(jmadill): figure out why this fails
314     if (IsIntel() && GetParam() == ES3_OPENGL())
315     {
316         std::cout << "Test skipped on Intel due to failures." << std::endl;
317         return;
318     }
319 
320     glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]);
321 
322     GLuint textures[2];
323     glGenTextures(2, &textures[0]);
324 
325     glBindTexture(GL_TEXTURE_2D, textures[0]);
326     glTexStorage2D(GL_TEXTURE_2D, 1, GL_SRGB8_ALPHA8, getWindowWidth(), getWindowHeight());
327     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0], 0);
328 
329     glBindTexture(GL_TEXTURE_2D, textures[1]);
330     glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, getWindowWidth(), getWindowHeight());
331     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, textures[1], 0);
332 
333     GLenum drawBuffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
334     glDrawBuffers(2, drawBuffers);
335 
336     // Clear both textures
337     glClearColor(0.5f, 0.5f, 0.5f, 0.5f);
338     glClear(GL_COLOR_BUFFER_BIT);
339 
340     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
341     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, 0, 0);
342 
343     // Check value of texture0
344     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0], 0);
345     EXPECT_PIXEL_NEAR(0, 0, 188, 188, 188, 128, 1.0);
346 
347     // Check value of texture1
348     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[1], 0);
349     EXPECT_PIXEL_NEAR(0, 0, 128, 128, 128, 128, 1.0);
350 }
351 
352 // This test covers a D3D11 bug where calling ClearRenderTargetView sometimes wouldn't sync
353 // before a draw call. The test draws small quads to a larger FBO (the default back buffer).
354 // Before each blit to the back buffer it clears the quad to a certain color using
355 // ClearBufferfv to give a solid color. The sync problem goes away if we insert a call to
356 // flush or finish after ClearBufferfv or each draw.
TEST_P(ClearTestES3,RepeatedClear)357 TEST_P(ClearTestES3, RepeatedClear)
358 {
359     if (IsD3D11() && (IsNVIDIA() || IsIntel()))
360     {
361         std::cout << "Test skipped on Nvidia and Intel D3D11." << std::endl;
362         return;
363     }
364 
365     const std::string &vertexSource =
366         "#version 300 es\n"
367         "in highp vec2 position;\n"
368         "out highp vec2 v_coord;\n"
369         "void main(void)\n"
370         "{\n"
371         "    gl_Position = vec4(position, 0, 1);\n"
372         "    vec2 texCoord = (position * 0.5) + 0.5;\n"
373         "    v_coord = texCoord;\n"
374         "}\n";
375 
376     const std::string &fragmentSource =
377         "#version 300 es\n"
378         "in highp vec2 v_coord;\n"
379         "out highp vec4 color;\n"
380         "uniform sampler2D tex;\n"
381         "void main()\n"
382         "{\n"
383         "    color = texture(tex, v_coord);\n"
384         "}\n";
385 
386     mProgram = CompileProgram(vertexSource, fragmentSource);
387     ASSERT_NE(0u, mProgram);
388 
389     mTextures.resize(1, 0);
390     glGenTextures(1, mTextures.data());
391 
392     GLenum format           = GL_RGBA8;
393     const int numRowsCols   = 3;
394     const int cellSize      = 32;
395     const int fboSize       = cellSize;
396     const int backFBOSize   = cellSize * numRowsCols;
397     const float fmtValueMin = 0.0f;
398     const float fmtValueMax = 1.0f;
399 
400     glBindTexture(GL_TEXTURE_2D, mTextures[0]);
401     glTexStorage2D(GL_TEXTURE_2D, 1, format, fboSize, fboSize);
402     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
403     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
404     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
405     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
406     ASSERT_GL_NO_ERROR();
407 
408     glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]);
409     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
410     ASSERT_GL_NO_ERROR();
411 
412     ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
413 
414     // larger fbo bound -- clear to transparent black
415     glUseProgram(mProgram);
416     GLint uniLoc = glGetUniformLocation(mProgram, "tex");
417     ASSERT_NE(-1, uniLoc);
418     glUniform1i(uniLoc, 0);
419     glBindTexture(GL_TEXTURE_2D, mTextures[0]);
420 
421     GLint positionLocation = glGetAttribLocation(mProgram, "position");
422     ASSERT_NE(-1, positionLocation);
423 
424     glUseProgram(mProgram);
425 
426     for (int cellY = 0; cellY < numRowsCols; cellY++)
427     {
428         for (int cellX = 0; cellX < numRowsCols; cellX++)
429         {
430             int seed            = cellX + cellY * numRowsCols;
431             const Vector4 color = RandomVec4(seed, fmtValueMin, fmtValueMax);
432 
433             glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]);
434             glClearBufferfv(GL_COLOR, 0, color.data());
435 
436             glBindFramebuffer(GL_FRAMEBUFFER, 0);
437 
438             // Method 1: Set viewport and draw full-viewport quad
439             glViewport(cellX * cellSize, cellY * cellSize, cellSize, cellSize);
440             drawQuad(mProgram, "position", 0.5f);
441 
442             // Uncommenting the glFinish call seems to make the test pass.
443             // glFinish();
444         }
445     }
446 
447     std::vector<GLColor> pixelData(backFBOSize * backFBOSize);
448     glReadPixels(0, 0, backFBOSize, backFBOSize, GL_RGBA, GL_UNSIGNED_BYTE, pixelData.data());
449 
450     for (int cellY = 0; cellY < numRowsCols; cellY++)
451     {
452         for (int cellX = 0; cellX < numRowsCols; cellX++)
453         {
454             int seed              = cellX + cellY * numRowsCols;
455             const Vector4 color   = RandomVec4(seed, fmtValueMin, fmtValueMax);
456             GLColor expectedColor = Vec4ToColor(color);
457 
458             int testN           = cellX * cellSize + cellY * backFBOSize * cellSize + backFBOSize + 1;
459             GLColor actualColor = pixelData[testN];
460             EXPECT_NEAR(expectedColor.R, actualColor.R, 1);
461             EXPECT_NEAR(expectedColor.G, actualColor.G, 1);
462             EXPECT_NEAR(expectedColor.B, actualColor.B, 1);
463             EXPECT_NEAR(expectedColor.A, actualColor.A, 1);
464         }
465     }
466 
467     ASSERT_GL_NO_ERROR();
468 }
469 
470 // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
471 ANGLE_INSTANTIATE_TEST(ClearTest,
472                        ES2_D3D9(),
473                        ES2_D3D11(),
474                        ES3_D3D11(),
475                        ES2_OPENGL(),
476                        ES3_OPENGL(),
477                        ES2_OPENGLES(),
478                        ES3_OPENGLES());
479 ANGLE_INSTANTIATE_TEST(ClearTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
480 
481 }  // anonymous namespace
482