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