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 #include "test_utils/gl_raii.h"
9
10 using namespace angle;
11
12 class DrawBuffersTest : public ANGLETest
13 {
14 protected:
DrawBuffersTest()15 DrawBuffersTest()
16 {
17 setWindowWidth(128);
18 setWindowHeight(128);
19 setConfigRedBits(8);
20 setConfigGreenBits(8);
21 setConfigBlueBits(8);
22 setConfigAlphaBits(8);
23 setConfigDepthBits(24);
24 }
25
testTearDown()26 void testTearDown() override
27 {
28 glDeleteFramebuffers(1, &mFBO);
29 glDeleteFramebuffers(1, &mReadFramebuffer);
30 glDeleteTextures(4, mTextures);
31 }
32
33 // We must call a different DrawBuffers method depending on extension support. Use this
34 // method instead of calling on directly.
setDrawBuffers(GLsizei n,const GLenum * drawBufs)35 void setDrawBuffers(GLsizei n, const GLenum *drawBufs)
36 {
37 if (IsGLExtensionEnabled("GL_EXT_draw_buffers"))
38 {
39 glDrawBuffersEXT(n, drawBufs);
40 }
41 else
42 {
43 ASSERT_GE(getClientMajorVersion(), 3);
44 glDrawBuffers(n, drawBufs);
45 }
46 }
47
48 // Use this method to filter if we can support these tests.
setupTest()49 bool setupTest()
50 {
51 if (getClientMajorVersion() < 3 && (!EnsureGLExtensionEnabled("GL_EXT_draw_buffers") ||
52 !EnsureGLExtensionEnabled("GL_ANGLE_framebuffer_blit")))
53 {
54 return false;
55 }
56
57 // This test seems to fail on an nVidia machine when the window is hidden
58 setWindowVisible(getOSWindow(), true);
59
60 glGenFramebuffers(1, &mFBO);
61 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFBO);
62
63 glGenTextures(4, mTextures);
64
65 for (size_t texIndex = 0; texIndex < ArraySize(mTextures); texIndex++)
66 {
67 glBindTexture(GL_TEXTURE_2D, mTextures[texIndex]);
68 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
69 GL_UNSIGNED_BYTE, nullptr);
70 }
71
72 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &mMaxDrawBuffers);
73
74 glGenFramebuffers(1, &mReadFramebuffer);
75 glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer);
76
77 return true;
78 }
79
setupMRTProgramESSL3(bool bufferEnabled[8],GLuint * programOut)80 void setupMRTProgramESSL3(bool bufferEnabled[8], GLuint *programOut)
81 {
82 std::stringstream strstr;
83
84 strstr << "#version 300 es\n"
85 "precision highp float;\n";
86
87 for (unsigned int index = 0; index < 8; index++)
88 {
89 if (bufferEnabled[index])
90 {
91 strstr << "layout(location = " << index
92 << ") "
93 "out vec4 value"
94 << index << ";\n";
95 }
96 }
97
98 strstr << "void main()\n"
99 "{\n";
100
101 for (unsigned int index = 0; index < 8; index++)
102 {
103 if (bufferEnabled[index])
104 {
105 unsigned int r = (index + 1) & 1;
106 unsigned int g = (index + 1) & 2;
107 unsigned int b = (index + 1) & 4;
108
109 strstr << " value" << index << " = vec4(" << r << ".0, " << g << ".0, " << b
110 << ".0, 1.0);\n";
111 }
112 }
113
114 strstr << "}\n";
115
116 *programOut = CompileProgram(essl3_shaders::vs::Simple(), strstr.str().c_str());
117 if (*programOut == 0)
118 {
119 FAIL() << "shader compilation failed.";
120 }
121 }
122
setupMRTProgramESSL1(bool bufferEnabled[8],GLuint * programOut)123 void setupMRTProgramESSL1(bool bufferEnabled[8], GLuint *programOut)
124 {
125 std::stringstream strstr;
126
127 strstr << "#extension GL_EXT_draw_buffers : enable\n"
128 "precision highp float;\n"
129 "void main()\n"
130 "{\n";
131
132 for (unsigned int index = 0; index < 8; index++)
133 {
134 if (bufferEnabled[index])
135 {
136 unsigned int r = (index + 1) & 1;
137 unsigned int g = (index + 1) & 2;
138 unsigned int b = (index + 1) & 4;
139
140 strstr << " gl_FragData[" << index << "] = vec4(" << r << ".0, " << g << ".0, "
141 << b << ".0, 1.0);\n";
142 }
143 }
144
145 strstr << "}\n";
146
147 *programOut = CompileProgram(essl1_shaders::vs::Simple(), strstr.str().c_str());
148 if (*programOut == 0)
149 {
150 FAIL() << "shader compilation failed.";
151 }
152 }
153
setupMRTProgram(bool bufferEnabled[8],GLuint * programOut)154 void setupMRTProgram(bool bufferEnabled[8], GLuint *programOut)
155 {
156 if (getClientMajorVersion() == 3)
157 {
158 setupMRTProgramESSL3(bufferEnabled, programOut);
159 }
160 else
161 {
162 ASSERT_EQ(getClientMajorVersion(), 2);
163 setupMRTProgramESSL1(bufferEnabled, programOut);
164 }
165 }
166
positionAttrib()167 const char *positionAttrib()
168 {
169 if (getClientMajorVersion() == 3)
170 {
171 return essl3_shaders::PositionAttrib();
172 }
173 else
174 {
175 return essl1_shaders::PositionAttrib();
176 }
177 }
178
getColorForIndex(unsigned int index)179 static GLColor getColorForIndex(unsigned int index)
180 {
181 GLubyte r = (((index + 1) & 1) > 0) ? 255 : 0;
182 GLubyte g = (((index + 1) & 2) > 0) ? 255 : 0;
183 GLubyte b = (((index + 1) & 4) > 0) ? 255 : 0;
184 return GLColor(r, g, b, 255u);
185 }
186
verifyAttachment2DColor(unsigned int index,GLuint textureName,GLenum target,GLint level,GLColor color)187 void verifyAttachment2DColor(unsigned int index,
188 GLuint textureName,
189 GLenum target,
190 GLint level,
191 GLColor color)
192 {
193 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, textureName,
194 level);
195 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, color)
196 << "index " << index;
197 }
198
verifyAttachment2DUnwritten(unsigned int index,GLuint texture,GLenum target,GLint level)199 void verifyAttachment2DUnwritten(unsigned int index, GLuint texture, GLenum target, GLint level)
200 {
201 verifyAttachment2DColor(index, texture, target, level, GLColor::transparentBlack);
202 }
203
verifyAttachment2D(unsigned int index,GLuint texture,GLenum target,GLint level)204 void verifyAttachment2D(unsigned int index, GLuint texture, GLenum target, GLint level)
205 {
206 verifyAttachment2DColor(index, texture, target, level, getColorForIndex(index));
207 }
208
verifyAttachment3DOES(unsigned int index,GLuint texture,GLint level,GLint layer)209 void verifyAttachment3DOES(unsigned int index, GLuint texture, GLint level, GLint layer)
210 {
211 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_3D"));
212
213 glFramebufferTexture3DOES(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, texture,
214 level, layer);
215 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, getColorForIndex(index));
216 }
217
verifyAttachmentLayer(unsigned int index,GLuint texture,GLint level,GLint layer)218 void verifyAttachmentLayer(unsigned int index, GLuint texture, GLint level, GLint layer)
219 {
220 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, level, layer);
221 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, getColorForIndex(index));
222 }
223
224 GLuint mFBO = 0;
225 GLuint mReadFramebuffer = 0;
226 GLuint mTextures[4] = {};
227 GLint mMaxDrawBuffers = 0;
228 };
229
230 class DrawBuffersWebGL2Test : public DrawBuffersTest
231 {
232 public:
DrawBuffersWebGL2Test()233 DrawBuffersWebGL2Test()
234 {
235 setWebGLCompatibilityEnabled(true);
236 setRobustResourceInit(true);
237 }
238 };
239
240 // Verify that GL_MAX_DRAW_BUFFERS returns the expected values for D3D11
TEST_P(DrawBuffersTest,VerifyD3DLimits)241 TEST_P(DrawBuffersTest, VerifyD3DLimits)
242 {
243 EGLPlatformParameters platform = GetParam().eglParameters;
244
245 ANGLE_SKIP_TEST_IF(platform.renderer != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE);
246
247 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &mMaxDrawBuffers);
248
249 if (platform.majorVersion == 9 && platform.minorVersion == 3)
250 {
251 // D3D11 Feature Level 9_3 supports 4 draw buffers
252 ASSERT_EQ(mMaxDrawBuffers, 4);
253 }
254 else
255 {
256 // D3D11 Feature Level 10_0+ supports 8 draw buffers
257 ASSERT_EQ(mMaxDrawBuffers, 8);
258 }
259 }
260
TEST_P(DrawBuffersTest,Gaps)261 TEST_P(DrawBuffersTest, Gaps)
262 {
263 ANGLE_SKIP_TEST_IF(!setupTest());
264
265 // TODO(syoussefi): Qualcomm driver crashes in the presence of VK_ATTACHMENT_UNUSED.
266 // http://anglebug.com/3423
267 ANGLE_SKIP_TEST_IF(IsVulkan() && IsAndroid());
268
269 // Fails on Intel Ubuntu 19.04 Mesa 19.0.2 Vulkan. http://anglebug.com/3616
270 ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel() && IsVulkan());
271
272 glBindTexture(GL_TEXTURE_2D, mTextures[0]);
273 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, mTextures[0], 0);
274
275 bool flags[8] = {false, true};
276
277 GLuint program;
278 setupMRTProgram(flags, &program);
279
280 const GLenum bufs[] = {GL_NONE, GL_COLOR_ATTACHMENT1};
281 setDrawBuffers(2, bufs);
282 drawQuad(program, positionAttrib(), 0.5);
283
284 verifyAttachment2D(1, mTextures[0], GL_TEXTURE_2D, 0);
285
286 glDeleteProgram(program);
287 }
288
289 // Test that blend works with gaps
TEST_P(DrawBuffersTest,BlendWithGaps)290 TEST_P(DrawBuffersTest, BlendWithGaps)
291 {
292 ANGLE_SKIP_TEST_IF(!setupTest());
293
294 // Qualcomm driver crashes in the presence of VK_ATTACHMENT_UNUSED.
295 // http://anglebug.com/3423
296 ANGLE_SKIP_TEST_IF(IsVulkan() && IsAndroid());
297
298 // Fails on Intel Ubuntu 19.04 Mesa 19.0.2 Vulkan. http://anglebug.com/3616
299 ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel() && IsVulkan());
300
301 // http://anglebug.com/5154
302 ANGLE_SKIP_TEST_IF(IsOSX() && IsIntel() && IsDesktopOpenGL());
303
304 glBindTexture(GL_TEXTURE_2D, mTextures[0]);
305 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, mTextures[0], 0);
306
307 ASSERT_GL_NO_ERROR();
308
309 bool flags[8] = {false, true};
310
311 GLuint program;
312 setupMRTProgram(flags, &program);
313
314 const GLenum bufs[] = {GL_NONE, GL_COLOR_ATTACHMENT1};
315 setDrawBuffers(2, bufs);
316
317 // Draws green into attachment 1
318 drawQuad(program, positionAttrib(), 0.5);
319 verifyAttachment2D(1, mTextures[0], GL_TEXTURE_2D, 0);
320 ASSERT_GL_NO_ERROR();
321
322 // Clear with red
323 glClearColor(1.0, 0.0, 0.0, 1.0);
324 glClear(GL_COLOR_BUFFER_BIT);
325 verifyAttachment2DColor(1, mTextures[0], GL_TEXTURE_2D, 0, GLColor(255u, 0, 0, 255u));
326
327 // Draw green into attachment 1 again but with blending, expecting yellow
328 glEnable(GL_BLEND);
329 glBlendFunc(GL_ONE, GL_ONE);
330 drawQuad(program, positionAttrib(), 0.5);
331 verifyAttachment2DColor(1, mTextures[0], GL_TEXTURE_2D, 0, GLColor(255u, 255u, 0, 255u));
332 ASSERT_GL_NO_ERROR();
333
334 glDeleteProgram(program);
335 }
336
337 // Test that clear works with gaps
TEST_P(DrawBuffersTest,ClearWithGaps)338 TEST_P(DrawBuffersTest, ClearWithGaps)
339 {
340 // TODO(syoussefi): Qualcomm driver crashes in the presence of VK_ATTACHMENT_UNUSED.
341 // http://anglebug.com/3423
342 ANGLE_SKIP_TEST_IF(IsVulkan() && IsAndroid());
343
344 ANGLE_SKIP_TEST_IF(!setupTest());
345
346 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &mMaxDrawBuffers);
347 ASSERT_GE(mMaxDrawBuffers, 4);
348
349 glBindTexture(GL_TEXTURE_2D, mTextures[0]);
350 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
351
352 glBindTexture(GL_TEXTURE_2D, mTextures[1]);
353 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, mTextures[1], 0);
354
355 const GLenum bufs[] = {GL_COLOR_ATTACHMENT0, GL_NONE, GL_NONE, GL_COLOR_ATTACHMENT3};
356
357 bool flags[8] = {true, false, false, true};
358 GLuint program;
359 setupMRTProgram(flags, &program);
360
361 setDrawBuffers(4, bufs);
362
363 glClearColor(1.0f, 1.0f, 0.0f, 1.0f);
364 glClear(GL_COLOR_BUFFER_BIT);
365
366 // A bogus draw to make sure clears are done with a render pass in the Vulkan backend.
367 glEnable(GL_BLEND);
368 glBlendFunc(GL_ZERO, GL_ONE);
369 drawQuad(program, positionAttrib(), 0.5);
370 EXPECT_GL_NO_ERROR();
371
372 verifyAttachment2DColor(0, mTextures[0], GL_TEXTURE_2D, 0, GLColor::yellow);
373 verifyAttachment2DColor(3, mTextures[1], GL_TEXTURE_2D, 0, GLColor::yellow);
374
375 EXPECT_GL_NO_ERROR();
376 }
377
TEST_P(DrawBuffersTest,FirstAndLast)378 TEST_P(DrawBuffersTest, FirstAndLast)
379 {
380 ANGLE_SKIP_TEST_IF(!setupTest());
381
382 // TODO(syoussefi): Qualcomm driver crashes in the presence of VK_ATTACHMENT_UNUSED.
383 // http://anglebug.com/3423
384 ANGLE_SKIP_TEST_IF(IsVulkan() && IsAndroid());
385
386 glBindTexture(GL_TEXTURE_2D, mTextures[0]);
387 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
388
389 glBindTexture(GL_TEXTURE_2D, mTextures[1]);
390 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, mTextures[1], 0);
391
392 bool flags[8] = {true, false, false, true};
393
394 GLuint program;
395 setupMRTProgram(flags, &program);
396
397 const GLenum bufs[] = {GL_COLOR_ATTACHMENT0, GL_NONE, GL_NONE, GL_COLOR_ATTACHMENT3};
398
399 setDrawBuffers(4, bufs);
400 drawQuad(program, positionAttrib(), 0.5);
401
402 verifyAttachment2D(0, mTextures[0], GL_TEXTURE_2D, 0);
403 verifyAttachment2D(3, mTextures[1], GL_TEXTURE_2D, 0);
404
405 EXPECT_GL_NO_ERROR();
406
407 glDeleteProgram(program);
408 }
409
TEST_P(DrawBuffersTest,FirstHalfNULL)410 TEST_P(DrawBuffersTest, FirstHalfNULL)
411 {
412 ANGLE_SKIP_TEST_IF(!setupTest());
413
414 // TODO(syoussefi): Qualcomm driver crashes in the presence of VK_ATTACHMENT_UNUSED.
415 // http://anglebug.com/3423
416 ANGLE_SKIP_TEST_IF(IsVulkan() && IsAndroid());
417
418 // Fails on Intel Ubuntu 19.04 Mesa 19.0.2 Vulkan. http://anglebug.com/3616
419 ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel() && IsVulkan());
420
421 bool flags[8] = {false};
422 GLenum bufs[8] = {GL_NONE};
423
424 GLuint halfMaxDrawBuffers = static_cast<GLuint>(mMaxDrawBuffers) / 2;
425
426 for (GLuint texIndex = 0; texIndex < halfMaxDrawBuffers; texIndex++)
427 {
428 glBindTexture(GL_TEXTURE_2D, mTextures[texIndex]);
429 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + halfMaxDrawBuffers + texIndex,
430 GL_TEXTURE_2D, mTextures[texIndex], 0);
431 flags[texIndex + halfMaxDrawBuffers] = true;
432 bufs[texIndex + halfMaxDrawBuffers] = GL_COLOR_ATTACHMENT0 + halfMaxDrawBuffers + texIndex;
433 }
434
435 GLuint program;
436 setupMRTProgram(flags, &program);
437
438 setDrawBuffers(mMaxDrawBuffers, bufs);
439 drawQuad(program, positionAttrib(), 0.5);
440
441 for (GLuint texIndex = 0; texIndex < halfMaxDrawBuffers; texIndex++)
442 {
443 verifyAttachment2D(texIndex + halfMaxDrawBuffers, mTextures[texIndex], GL_TEXTURE_2D, 0);
444 }
445
446 EXPECT_GL_NO_ERROR();
447
448 glDeleteProgram(program);
449 }
450
451 // Test that non-zero draw buffers can be queried on the default framebuffer
TEST_P(DrawBuffersTest,DefaultFramebufferDrawBufferQuery)452 TEST_P(DrawBuffersTest, DefaultFramebufferDrawBufferQuery)
453 {
454 ANGLE_SKIP_TEST_IF(!setupTest());
455
456 glBindFramebuffer(GL_FRAMEBUFFER, 0);
457
458 GLint drawbuffer = 0;
459 glGetIntegerv(GL_DRAW_BUFFER1, &drawbuffer);
460 EXPECT_GL_NO_ERROR();
461
462 EXPECT_EQ(GL_NONE, drawbuffer);
463 }
464
465 // Same as above but adds a state change from a program with different masks after a clear.
TEST_P(DrawBuffersWebGL2Test,TwoProgramsWithDifferentOutputsAndClear)466 TEST_P(DrawBuffersWebGL2Test, TwoProgramsWithDifferentOutputsAndClear)
467 {
468 // TODO(http://anglebug.com/2872): Broken on the GL back-end.
469 ANGLE_SKIP_TEST_IF(IsOpenGL());
470
471 // TODO(syoussefi): Qualcomm driver crashes in the presence of VK_ATTACHMENT_UNUSED.
472 // http://anglebug.com/3423
473 ANGLE_SKIP_TEST_IF(IsVulkan() && IsAndroid());
474
475 ANGLE_SKIP_TEST_IF(!setupTest());
476
477 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &mMaxDrawBuffers);
478 ASSERT_GE(mMaxDrawBuffers, 4);
479
480 bool flags[8] = {false};
481 GLenum someBufs[4] = {GL_NONE};
482 GLenum allBufs[4] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2,
483 GL_COLOR_ATTACHMENT3};
484
485 constexpr GLuint kMaxBuffers = 4;
486 constexpr GLuint kHalfMaxBuffers = 2;
487
488 // Enable all draw buffers.
489 for (GLuint texIndex = 0; texIndex < kMaxBuffers; texIndex++)
490 {
491 glBindTexture(GL_TEXTURE_2D, mTextures[texIndex]);
492 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + texIndex, GL_TEXTURE_2D,
493 mTextures[texIndex], 0);
494 someBufs[texIndex] =
495 texIndex >= kHalfMaxBuffers ? GL_COLOR_ATTACHMENT0 + texIndex : GL_NONE;
496
497 // Mask out the first two buffers.
498 flags[texIndex] = texIndex >= kHalfMaxBuffers;
499 }
500
501 GLuint program;
502 setupMRTProgram(flags, &program);
503
504 // Now set up a second simple program that draws to FragColor. Should be broadcast.
505 ANGLE_GL_PROGRAM(simpleProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
506
507 // Draw with simple program.
508 drawQuad(simpleProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
509 ASSERT_GL_NO_ERROR();
510
511 // Clear draw buffers.
512 setDrawBuffers(kMaxBuffers, someBufs);
513 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
514 glClear(GL_COLOR_BUFFER_BIT);
515
516 ASSERT_GL_NO_ERROR();
517
518 // Verify first is drawn red, second is untouched, and last two are cleared green.
519 verifyAttachment2DColor(0, mTextures[0], GL_TEXTURE_2D, 0, GLColor::red);
520 verifyAttachment2DColor(1, mTextures[1], GL_TEXTURE_2D, 0, GLColor::transparentBlack);
521 verifyAttachment2DColor(2, mTextures[2], GL_TEXTURE_2D, 0, GLColor::green);
522 verifyAttachment2DColor(3, mTextures[3], GL_TEXTURE_2D, 0, GLColor::green);
523
524 // Draw with MRT program.
525 setDrawBuffers(kMaxBuffers, someBufs);
526 drawQuad(program, positionAttrib(), 0.5, 1.0f, true);
527 ASSERT_GL_NO_ERROR();
528
529 // Only the last two attachments should be updated.
530 verifyAttachment2DColor(0, mTextures[0], GL_TEXTURE_2D, 0, GLColor::red);
531 verifyAttachment2DColor(1, mTextures[1], GL_TEXTURE_2D, 0, GLColor::transparentBlack);
532 verifyAttachment2D(2, mTextures[2], GL_TEXTURE_2D, 0);
533 verifyAttachment2D(3, mTextures[3], GL_TEXTURE_2D, 0);
534
535 // Active draw buffers with no fragment output is not allowed.
536 setDrawBuffers(kMaxBuffers, allBufs);
537 drawQuad(program, positionAttrib(), 0.5, 1.0f, true);
538 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
539 // Exception: when RASTERIZER_DISCARD is enabled.
540 glEnable(GL_RASTERIZER_DISCARD);
541 drawQuad(program, positionAttrib(), 0.5, 1.0f, true);
542 ASSERT_GL_NO_ERROR();
543 glDisable(GL_RASTERIZER_DISCARD);
544 // Exception: when all 4 channels of color mask are set to false.
545 glColorMask(false, false, false, false);
546 drawQuad(program, positionAttrib(), 0.5, 1.0f, true);
547 ASSERT_GL_NO_ERROR();
548 glColorMask(false, true, false, false);
549 drawQuad(program, positionAttrib(), 0.5, 1.0f, true);
550 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
551 glColorMask(true, true, true, true);
552 drawQuad(program, positionAttrib(), 0.5, 1.0f, true);
553 ASSERT_GL_ERROR(GL_INVALID_OPERATION);
554
555 // Clear again. All attachments should be cleared.
556 glClear(GL_COLOR_BUFFER_BIT);
557 verifyAttachment2DColor(0, mTextures[0], GL_TEXTURE_2D, 0, GLColor::green);
558 verifyAttachment2DColor(1, mTextures[1], GL_TEXTURE_2D, 0, GLColor::green);
559 verifyAttachment2DColor(2, mTextures[2], GL_TEXTURE_2D, 0, GLColor::green);
560 verifyAttachment2DColor(3, mTextures[3], GL_TEXTURE_2D, 0, GLColor::green);
561
562 glDeleteProgram(program);
563 }
564
565 // Test clear with gaps in draw buffers, originally show up as
566 // webgl_conformance_vulkan_passthrough_tests conformance/extensions/webgl-draw-buffers.html
567 // failure. This is added for ease of debugging.
TEST_P(DrawBuffersWebGL2Test,Clear)568 TEST_P(DrawBuffersWebGL2Test, Clear)
569 {
570 ANGLE_SKIP_TEST_IF(!setupTest());
571
572 constexpr GLint kMaxBuffers = 4;
573
574 glGetIntegerv(GL_MAX_DRAW_BUFFERS, &mMaxDrawBuffers);
575 ASSERT_GE(mMaxDrawBuffers, kMaxBuffers);
576
577 GLenum drawBufs[kMaxBuffers] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
578 GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3};
579
580 // Enable all draw buffers.
581 for (GLuint texIndex = 0; texIndex < kMaxBuffers; texIndex++)
582 {
583 glBindTexture(GL_TEXTURE_2D, mTextures[texIndex]);
584 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + texIndex, GL_TEXTURE_2D,
585 mTextures[texIndex], 0);
586 }
587
588 // Clear with all draw buffers.
589 setDrawBuffers(kMaxBuffers, drawBufs);
590 glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
591 glClear(GL_COLOR_BUFFER_BIT);
592
593 // Clear with first half none draw buffers.
594 drawBufs[0] = GL_NONE;
595 drawBufs[1] = GL_NONE;
596 setDrawBuffers(kMaxBuffers, drawBufs);
597 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
598 glClear(GL_COLOR_BUFFER_BIT);
599
600 ASSERT_GL_NO_ERROR();
601
602 // Verify first is drawn red, second is untouched, and last two are cleared green.
603 verifyAttachment2DColor(0, mTextures[0], GL_TEXTURE_2D, 0, GLColor::red);
604 verifyAttachment2DColor(1, mTextures[1], GL_TEXTURE_2D, 0, GLColor::red);
605 verifyAttachment2DColor(2, mTextures[2], GL_TEXTURE_2D, 0, GLColor::green);
606 verifyAttachment2DColor(3, mTextures[3], GL_TEXTURE_2D, 0, GLColor::green);
607 }
608
TEST_P(DrawBuffersTest,UnwrittenOutputVariablesShouldNotCrash)609 TEST_P(DrawBuffersTest, UnwrittenOutputVariablesShouldNotCrash)
610 {
611 ANGLE_SKIP_TEST_IF(!setupTest());
612
613 // Bind two render targets but use a shader which writes only to the first one.
614 glBindTexture(GL_TEXTURE_2D, mTextures[0]);
615 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
616
617 glBindTexture(GL_TEXTURE_2D, mTextures[1]);
618 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, mTextures[1], 0);
619
620 bool flags[8] = {true, false};
621
622 GLuint program;
623 setupMRTProgram(flags, &program);
624
625 const GLenum bufs[] = {
626 GL_COLOR_ATTACHMENT0,
627 GL_COLOR_ATTACHMENT1,
628 GL_NONE,
629 GL_NONE,
630 };
631
632 setDrawBuffers(4, bufs);
633
634 // This call should not crash when we dynamically generate the HLSL code.
635 drawQuad(program, positionAttrib(), 0.5);
636
637 verifyAttachment2D(0, mTextures[0], GL_TEXTURE_2D, 0);
638
639 EXPECT_GL_NO_ERROR();
640
641 glDeleteProgram(program);
642 }
643
TEST_P(DrawBuffersTest,BroadcastGLFragColor)644 TEST_P(DrawBuffersTest, BroadcastGLFragColor)
645 {
646 // Broadcast is not supported on GLES 3.0.
647 ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
648 ANGLE_SKIP_TEST_IF(!setupTest());
649
650 // Bind two render targets. gl_FragColor should be broadcast to both.
651 glBindTexture(GL_TEXTURE_2D, mTextures[0]);
652 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
653
654 glBindTexture(GL_TEXTURE_2D, mTextures[1]);
655 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, mTextures[1], 0);
656
657 const GLenum bufs[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
658
659 constexpr char kFS[] =
660 "#extension GL_EXT_draw_buffers : enable\n"
661 "precision highp float;\n"
662 "uniform float u_zero;\n"
663 "void main()\n"
664 "{\n"
665 " gl_FragColor = vec4(1, 0, 0, 1);\n"
666 " if (u_zero < 1.0)\n"
667 " {\n"
668 " return;\n"
669 " }\n"
670 "}\n";
671
672 GLuint program = CompileProgram(essl1_shaders::vs::Simple(), kFS);
673 if (program == 0)
674 {
675 FAIL() << "shader compilation failed.";
676 }
677
678 setDrawBuffers(2, bufs);
679 drawQuad(program, essl1_shaders::PositionAttrib(), 0.5);
680
681 verifyAttachment2D(0, mTextures[0], GL_TEXTURE_2D, 0);
682 verifyAttachment2D(0, mTextures[1], GL_TEXTURE_2D, 0);
683
684 EXPECT_GL_NO_ERROR();
685
686 glDeleteProgram(program);
687 }
688
689 // Test that binding multiple layers of a 3D texture works correctly.
690 // This is the same as DrawBuffersTestES3.3DTextures but is used for GL_OES_texture_3D extension
691 // on GLES 2.0 instead.
692 TEST_P(DrawBuffersTest, 3DTexturesOES)
693 {
694 ANGLE_SKIP_TEST_IF(!setupTest());
695 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_3D"));
696
697 GLTexture texture;
698 glBindTexture(GL_TEXTURE_3D, texture.get());
699 glTexImage3DOES(GL_TEXTURE_3D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(),
700 getWindowWidth(), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
701
702 glFramebufferTexture3DOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, texture.get(), 0,
703 0);
704 glFramebufferTexture3DOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_3D, texture.get(), 0,
705 1);
706 glFramebufferTexture3DOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_3D, texture.get(), 0,
707 2);
708 glFramebufferTexture3DOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_3D, texture.get(), 0,
709 3);
710
711 bool flags[8] = {true, true, true, true, false};
712
713 GLuint program;
714 setupMRTProgram(flags, &program);
715
716 const GLenum bufs[] = {
717 GL_COLOR_ATTACHMENT0,
718 GL_COLOR_ATTACHMENT1,
719 GL_COLOR_ATTACHMENT2,
720 GL_COLOR_ATTACHMENT3,
721 };
722
723 setDrawBuffers(4, bufs);
724 drawQuad(program, positionAttrib(), 0.5);
725
726 verifyAttachment3DOES(0, texture.get(), 0, 0);
727 verifyAttachment3DOES(1, texture.get(), 0, 1);
728 verifyAttachment3DOES(2, texture.get(), 0, 2);
729 verifyAttachment3DOES(3, texture.get(), 0, 3);
730
731 EXPECT_GL_NO_ERROR();
732
733 glDeleteProgram(program);
734 }
735
736 class DrawBuffersTestES3 : public DrawBuffersTest
737 {};
738
739 // Test that binding multiple layers of a 3D texture works correctly
740 TEST_P(DrawBuffersTestES3, 3DTextures)
741 {
742 ANGLE_SKIP_TEST_IF(!setupTest());
743
744 GLTexture texture;
745 glBindTexture(GL_TEXTURE_3D, texture.get());
746 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), getWindowWidth(),
747 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
748
749 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.get(), 0, 0);
750 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture.get(), 0, 1);
751 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, texture.get(), 0, 2);
752 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, texture.get(), 0, 3);
753
754 bool flags[8] = {true, true, true, true, false};
755
756 GLuint program;
757 setupMRTProgram(flags, &program);
758
759 const GLenum bufs[] = {
760 GL_COLOR_ATTACHMENT0,
761 GL_COLOR_ATTACHMENT1,
762 GL_COLOR_ATTACHMENT2,
763 GL_COLOR_ATTACHMENT3,
764 };
765
766 glDrawBuffers(4, bufs);
767 drawQuad(program, positionAttrib(), 0.5);
768
769 verifyAttachmentLayer(0, texture.get(), 0, 0);
770 verifyAttachmentLayer(1, texture.get(), 0, 1);
771 verifyAttachmentLayer(2, texture.get(), 0, 2);
772 verifyAttachmentLayer(3, texture.get(), 0, 3);
773
774 EXPECT_GL_NO_ERROR();
775
776 glDeleteProgram(program);
777 }
778
779 // Test that binding multiple layers of a 2D array texture works correctly
780 TEST_P(DrawBuffersTestES3, 2DArrayTextures)
781 {
782 ANGLE_SKIP_TEST_IF(!setupTest());
783
784 GLTexture texture;
785 glBindTexture(GL_TEXTURE_2D_ARRAY, texture.get());
786 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, getWindowWidth(), getWindowHeight(),
787 getWindowWidth(), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
788
789 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.get(), 0, 0);
790 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture.get(), 0, 1);
791 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, texture.get(), 0, 2);
792 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, texture.get(), 0, 3);
793
794 bool flags[8] = {true, true, true, true, false};
795
796 GLuint program;
797 setupMRTProgram(flags, &program);
798
799 const GLenum bufs[] = {
800 GL_COLOR_ATTACHMENT0,
801 GL_COLOR_ATTACHMENT1,
802 GL_COLOR_ATTACHMENT2,
803 GL_COLOR_ATTACHMENT3,
804 };
805
806 glDrawBuffers(4, bufs);
807 drawQuad(program, positionAttrib(), 0.5);
808
809 verifyAttachmentLayer(0, texture.get(), 0, 0);
810 verifyAttachmentLayer(1, texture.get(), 0, 1);
811 verifyAttachmentLayer(2, texture.get(), 0, 2);
812 verifyAttachmentLayer(3, texture.get(), 0, 3);
813
814 EXPECT_GL_NO_ERROR();
815
816 glDeleteProgram(program);
817 }
818
819 // Test that blend works when draw buffers and framebuffers change.
TEST_P(DrawBuffersTestES3,BlendWithDrawBufferAndFramebufferChanges)820 TEST_P(DrawBuffersTestES3, BlendWithDrawBufferAndFramebufferChanges)
821 {
822 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_draw_buffers_indexed"));
823
824 // Qualcomm driver crashes in the presence of VK_ATTACHMENT_UNUSED.
825 // http://anglebug.com/3423
826 ANGLE_SKIP_TEST_IF(IsVulkan() && IsAndroid());
827
828 // Fails on Intel Ubuntu 19.04 Mesa 19.0.2 Vulkan. http://anglebug.com/3616
829 ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel() && IsVulkan());
830
831 // http://anglebug.com/5154
832 ANGLE_SKIP_TEST_IF(IsOSX() && IsIntel() && IsDesktopOpenGL());
833
834 // Create two framebuffers, one with 3 attachments (fbo3), one with 4 (fbo4). The test issues
835 // draw calls on fbo3 with different attachments enabled, then switches to fbo4 (without
836 // dirtying blend state) and draws to other attachments. It ensures that blend state is
837 // appropriately set on framebuffer change.
838
839 GLenum bufs[4] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2,
840 GL_COLOR_ATTACHMENT3};
841
842 GLFramebuffer fbo[2];
843 GLTexture tex[7];
844 constexpr GLfloat kClearValue[] = {1, 1, 1, 1};
845
846 glBindFramebuffer(GL_FRAMEBUFFER, fbo[0]);
847
848 for (uint32_t texIndex = 0; texIndex < 7; ++texIndex)
849 {
850 size_t colorAttachmentIndex = texIndex >= 3 ? texIndex - 3 : texIndex;
851 if (texIndex == 3)
852 {
853 glBindFramebuffer(GL_FRAMEBUFFER, fbo[1]);
854 }
855
856 glBindTexture(GL_TEXTURE_2D, tex[texIndex]);
857 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
858 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + colorAttachmentIndex,
859 GL_TEXTURE_2D, tex[texIndex], 0);
860 EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
861
862 glDrawBuffers(4, bufs);
863 glClearBufferfv(GL_COLOR, colorAttachmentIndex, kClearValue);
864 }
865 ASSERT_GL_NO_ERROR();
866
867 glEnablei(GL_BLEND, 0);
868 glEnablei(GL_BLEND, 1);
869 glEnablei(GL_BLEND, 2);
870 glEnablei(GL_BLEND, 3);
871
872 glBlendEquationi(0, GL_FUNC_REVERSE_SUBTRACT);
873 glBlendEquationi(1, GL_MIN);
874 glBlendEquationi(2, GL_FUNC_REVERSE_SUBTRACT);
875 glBlendEquationi(3, GL_FUNC_REVERSE_SUBTRACT);
876
877 glBlendFunci(0, GL_ONE, GL_ONE);
878 glBlendFunci(1, GL_DST_ALPHA, GL_DST_ALPHA);
879 glBlendFunci(2, GL_SRC_ALPHA, GL_SRC_ALPHA);
880 glBlendFunci(3, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
881
882 bufs[0] = GL_NONE;
883 bufs[2] = GL_NONE;
884 glDrawBuffers(4, bufs);
885
886 glBindFramebuffer(GL_FRAMEBUFFER, fbo[0]);
887
888 bufs[2] = GL_COLOR_ATTACHMENT2;
889 glDrawBuffers(3, bufs);
890
891 constexpr char kFS[] = R"(#version 300 es
892 precision highp float;
893
894 uniform vec4 value0;
895 uniform vec4 value1;
896 uniform vec4 value2;
897 uniform vec4 value3;
898
899 layout(location = 0) out vec4 color0;
900 layout(location = 1) out vec4 color1;
901 layout(location = 2) out vec4 color2;
902 layout(location = 3) out vec4 color3;
903
904 void main()
905 {
906 color0 = value0;
907 color1 = value1;
908 color2 = value2;
909 color3 = value3;
910 }
911 )";
912
913 ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
914 glUseProgram(program);
915
916 GLint uniforms[4];
917 for (uint32_t attachmentIndex = 0; attachmentIndex < 4; ++attachmentIndex)
918 {
919 char uniformName[20];
920 snprintf(uniformName, sizeof uniformName, "value%u", attachmentIndex);
921 uniforms[attachmentIndex] = glGetUniformLocation(program, uniformName);
922 ASSERT_NE(uniforms[attachmentIndex], -1);
923 }
924
925 // Currently, fbo3 is bound. The attachment states are:
926 //
927 // 0: DISABLED Color: (1, 1, 1, 1), Blend: reverse subtract, ONE/ONE
928 // 1: Color: (1, 1, 1, 1), Blend: min, DST_ALPHA/DST_ALPHA
929 // 2: Color: (1, 1, 1, 1), Blend: reverse subtract, SRC_ALPHA/SRC_ALPHA
930 //
931 // Draw:
932 //
933 // 0: Color: don't care
934 // 1: Color: (0.75, 0.5, 0.25, 0.5) -> Result after blend is: (0.75, 0.5, 0.25, 0.5)
935 // 2: Color: (0.25, 0.5, 0.75, 0.5) -> Result after blend is: (0.375, 0.25, 0.125, 0.25)
936
937 // Draws green into attachment 1
938 glUniform4f(uniforms[1], 0.75, 0.5, 0.25, 0.5);
939 glUniform4f(uniforms[2], 0.25, 0.5, 0.75, 0.5);
940 drawQuad(program, positionAttrib(), 0.5);
941 ASSERT_GL_NO_ERROR();
942
943 bufs[0] = GL_COLOR_ATTACHMENT0;
944 bufs[1] = GL_NONE;
945 glDrawBuffers(3, bufs);
946
947 // Currently, fbo3 is bound. The attachment states are:
948 //
949 // 0: Color: (1, 1, 1, 1), Blend: reverse subtract, ONE/ONE
950 // 1: DISABLED Color: (0.75, 0.5, 0.25, 0.5), Blend: min, DST_ALPHA/DST_ALPHA
951 // 2: Color: (0.375, 0.25, 0.125, 0.25), Blend: reverse subtract,
952 // SRC_ALPHA/SRC_ALPHA
953 //
954 // Draw:
955 //
956 // 0: Color: (0.5, 0.25, 0.75, 0.25) -> Result after blend is: (0.5, 0.75, 0.25, 0.75)
957 // 1: Color: don't care
958 // 2: Color: (0.125, 0, 0, 1) -> Result after blend is: (0.25, 0.25, 0.125, 0)
959
960 // Clear with red
961 glUniform4f(uniforms[0], 0.5, 0.25, 0.75, 0.25);
962 glUniform4f(uniforms[2], 0.125, 0, 0, 1);
963 drawQuad(program, positionAttrib(), 0.5);
964 ASSERT_GL_NO_ERROR();
965
966 glBindFramebuffer(GL_FRAMEBUFFER, fbo[1]);
967
968 // Currently, fbo4 is bound. The attachment states are:
969 //
970 // 0: DISABLED Color: (1, 1, 1, 1), Blend: reverse subtract, ONE/ONE
971 // 1: Color: (1, 1, 1, 1), Blend: min, DST_ALPHA/DST_ALPHA
972 // 2: DISABLED Color: (1, 1, 1, 1), Blend: reverse subtract, SRC_ALPHA/SRC_ALPHA
973 // 3: Color: (1, 1, 1, 1), Blend: reverse subtract, ONE_MINUS_SRC_ALPHA/SRC_ALPHA
974 //
975 // Draw:
976 //
977 // 0: Color: don't care
978 // 1: Color: (0.125, 0.5, 0.625, 0.25) -> Result after blend is: (0.125, 0.5, 0.625, 0.25)
979 // 2: Color: don't care
980 // 3: Color: (0.75, 0.25, 0.5, 0.75) -> Result after blend is:
981 // (0.5625, 0.6875, 0.625, 0.5625)
982
983 glUniform4f(uniforms[1], 0.125, 0.5, 0.625, 0.25);
984 glUniform4f(uniforms[3], 0.75, 0.25, 0.5, 0.75);
985 drawQuad(program, positionAttrib(), 0.5);
986 ASSERT_GL_NO_ERROR();
987
988 // Verify results
989 glBindFramebuffer(GL_FRAMEBUFFER, fbo[0]);
990 glReadBuffer(GL_COLOR_ATTACHMENT0);
991 EXPECT_PIXEL_NEAR(0, 0, 127, 191, 63, 191, 1);
992 glReadBuffer(GL_COLOR_ATTACHMENT1);
993 EXPECT_PIXEL_NEAR(0, 0, 191, 127, 63, 127, 1);
994 glReadBuffer(GL_COLOR_ATTACHMENT2);
995 EXPECT_PIXEL_NEAR(0, 0, 63, 63, 31, 0, 1);
996
997 glBindFramebuffer(GL_FRAMEBUFFER, fbo[1]);
998 glReadBuffer(GL_COLOR_ATTACHMENT0);
999 EXPECT_PIXEL_NEAR(0, 0, 255, 255, 255, 255, 1);
1000 glReadBuffer(GL_COLOR_ATTACHMENT1);
1001 EXPECT_PIXEL_NEAR(0, 0, 31, 127, 159, 63, 1);
1002 glReadBuffer(GL_COLOR_ATTACHMENT2);
1003 EXPECT_PIXEL_NEAR(0, 0, 255, 255, 255, 255, 1);
1004 glReadBuffer(GL_COLOR_ATTACHMENT3);
1005 EXPECT_PIXEL_NEAR(0, 0, 143, 175, 159, 143, 1);
1006 }
1007
1008 // Vulkan backend is setting per buffer color mask to false for draw buffers that set to GL_NONE.
1009 // These set of tests are to test draw buffer change followed by draw/clear/blit and followed by
1010 // draw buffer change are behaving correctly.
1011 class ColorMaskForDrawBuffersTest : public DrawBuffersTest
1012 {
1013 protected:
setupColorMaskForDrawBuffersTest()1014 void setupColorMaskForDrawBuffersTest()
1015 {
1016 glBindTexture(GL_TEXTURE_2D, mTextures[0]);
1017 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0],
1018 0);
1019 glBindTexture(GL_TEXTURE_2D, mTextures[1]);
1020 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, mTextures[1],
1021 0);
1022 glBindTexture(GL_TEXTURE_2D, mTextures[2]);
1023 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, mTextures[2],
1024 0);
1025
1026 constexpr char kFS_ESSL3[] =
1027 "#version 300 es\n"
1028 "precision highp float;\n"
1029 "uniform mediump vec4 u_color0;\n"
1030 "uniform mediump vec4 u_color1;\n"
1031 "uniform mediump vec4 u_color2;\n"
1032 "layout(location = 0) out vec4 out_color0;\n"
1033 "layout(location = 1) out vec4 out_color1;\n"
1034 "layout(location = 2) out vec4 out_color2;\n"
1035 "void main()\n"
1036 "{\n"
1037 " out_color0 = u_color0;\n"
1038 " out_color1 = u_color1;\n"
1039 " out_color2 = u_color2;\n"
1040 "}\n";
1041 program = CompileProgram(essl3_shaders::vs::Simple(), kFS_ESSL3);
1042 glUseProgram(program);
1043
1044 positionLocation = glGetAttribLocation(program, positionAttrib());
1045 ASSERT_NE(-1, positionLocation);
1046 color0UniformLocation = glGetUniformLocation(program, "u_color0");
1047 ASSERT_NE(color0UniformLocation, -1);
1048 color1UniformLocation = glGetUniformLocation(program, "u_color1");
1049 ASSERT_NE(color1UniformLocation, -1);
1050 color2UniformLocation = glGetUniformLocation(program, "u_color2");
1051 ASSERT_NE(color2UniformLocation, -1);
1052
1053 glUniform4fv(color0UniformLocation, 1, GLColor::red.toNormalizedVector().data());
1054 glUniform4fv(color1UniformLocation, 1, GLColor::green.toNormalizedVector().data());
1055 glUniform4fv(color2UniformLocation, 1, GLColor::yellow.toNormalizedVector().data());
1056
1057 // First draw into both buffers so that buffer0 is red and buffer1 is green
1058 resetDrawBuffers();
1059 drawQuad(program, positionAttrib(), 0.5);
1060 EXPECT_GL_NO_ERROR();
1061
1062 for (int i = 0; i < 4; i++)
1063 {
1064 drawBuffers[i] = GL_NONE;
1065 }
1066 }
1067
resetDrawBuffers()1068 void resetDrawBuffers()
1069 {
1070 drawBuffers[0] = GL_COLOR_ATTACHMENT0;
1071 drawBuffers[1] = GL_COLOR_ATTACHMENT1;
1072 drawBuffers[2] = GL_COLOR_ATTACHMENT2;
1073 drawBuffers[3] = GL_NONE;
1074 setDrawBuffers(4, drawBuffers);
1075 }
1076
1077 GLenum drawBuffers[4];
1078 GLuint program;
1079 GLint positionLocation;
1080 GLint color0UniformLocation;
1081 GLint color1UniformLocation;
1082 GLint color2UniformLocation;
1083 };
1084
1085 // Test draw buffer state change followed draw call
TEST_P(ColorMaskForDrawBuffersTest,DrawQuad)1086 TEST_P(ColorMaskForDrawBuffersTest, DrawQuad)
1087 {
1088 ANGLE_SKIP_TEST_IF(!setupTest());
1089 setupColorMaskForDrawBuffersTest();
1090
1091 // Draw blue into attachment0. Buffer0 should be blue and buffer1 should remain green
1092 drawBuffers[0] = GL_COLOR_ATTACHMENT0;
1093 setDrawBuffers(4, drawBuffers);
1094 glUniform4fv(color0UniformLocation, 1, GLColor::blue.toNormalizedVector().data());
1095 glUniform4fv(color1UniformLocation, 1, GLColor::cyan.toNormalizedVector().data());
1096 glViewport(0, 0, getWindowWidth() / 2, getWindowHeight() / 2);
1097 drawQuad(program, positionAttrib(), 0.5);
1098
1099 resetDrawBuffers();
1100 glUniform4fv(color0UniformLocation, 1, GLColor::magenta.toNormalizedVector().data());
1101 glUniform4fv(color1UniformLocation, 1, GLColor::white.toNormalizedVector().data());
1102 glViewport(getWindowWidth() / 2, 0, getWindowWidth() / 2, getWindowHeight() / 2);
1103 drawQuad(program, positionAttrib(), 0.5);
1104 EXPECT_GL_NO_ERROR();
1105
1106 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0],
1107 0);
1108 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
1109 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() / 4, GLColor::magenta);
1110 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() * 3 / 4, GLColor::red);
1111 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[1],
1112 0);
1113 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::green);
1114 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() / 4, GLColor::white);
1115 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() * 3 / 4, GLColor::green);
1116 EXPECT_GL_NO_ERROR();
1117 }
1118
1119 // Test draw buffer state change followed clear
TEST_P(ColorMaskForDrawBuffersTest,Clear)1120 TEST_P(ColorMaskForDrawBuffersTest, Clear)
1121 {
1122 ANGLE_SKIP_TEST_IF(!setupTest());
1123 setupColorMaskForDrawBuffersTest();
1124
1125 // Clear attachment1. Buffer0 should retain red and buffer1 should be blue
1126 drawBuffers[1] = GL_COLOR_ATTACHMENT1;
1127 setDrawBuffers(4, drawBuffers);
1128 angle::Vector4 clearColor = GLColor::blue.toNormalizedVector();
1129 glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
1130 glClear(GL_COLOR_BUFFER_BIT);
1131 verifyAttachment2DColor(0, mTextures[0], GL_TEXTURE_2D, 0, GLColor::red);
1132 verifyAttachment2DColor(1, mTextures[1], GL_TEXTURE_2D, 0, GLColor::blue);
1133 EXPECT_GL_NO_ERROR();
1134 }
1135
1136 // Test draw buffer state change followed scissored clear
TEST_P(ColorMaskForDrawBuffersTest,ScissoredClear)1137 TEST_P(ColorMaskForDrawBuffersTest, ScissoredClear)
1138 {
1139 ANGLE_SKIP_TEST_IF(!setupTest());
1140 setupColorMaskForDrawBuffersTest();
1141
1142 // Clear attachment1. Buffer0 should retain red and buffer1 should be blue
1143 drawBuffers[1] = GL_COLOR_ATTACHMENT1;
1144 setDrawBuffers(4, drawBuffers);
1145 angle::Vector4 clearColor = GLColor::blue.toNormalizedVector();
1146 glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
1147 glScissor(0, 0, getWindowWidth() / 2, getWindowHeight() / 2);
1148 glEnable(GL_SCISSOR_TEST);
1149 glClear(GL_COLOR_BUFFER_BIT);
1150
1151 resetDrawBuffers();
1152 clearColor = GLColor::magenta.toNormalizedVector();
1153 glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
1154 glScissor(getWindowWidth() / 2, 0, getWindowWidth() / 2, getWindowHeight() / 2);
1155 glClear(GL_COLOR_BUFFER_BIT);
1156 EXPECT_GL_NO_ERROR();
1157
1158 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0],
1159 0);
1160 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::red);
1161 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() / 4, GLColor::magenta);
1162 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() * 3 / 4, GLColor::red);
1163 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[1],
1164 0);
1165 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
1166 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() / 4, GLColor::magenta);
1167 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() * 3 / 4, GLColor::green);
1168 EXPECT_GL_NO_ERROR();
1169 }
1170
1171 // Test draw buffer state change followed FBO blit
TEST_P(ColorMaskForDrawBuffersTest,Blit)1172 TEST_P(ColorMaskForDrawBuffersTest, Blit)
1173 {
1174 ANGLE_SKIP_TEST_IF(!setupTest());
1175 setupColorMaskForDrawBuffersTest();
1176
1177 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[2],
1178 0);
1179
1180 // BLIT mTexture[2] to attachment0. Buffer0 should remain red and buffer1 should be yellow
1181 drawBuffers[0] = GL_COLOR_ATTACHMENT0;
1182 setDrawBuffers(4, drawBuffers);
1183 glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(),
1184 getWindowHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
1185 verifyAttachment2DColor(0, mTextures[0], GL_TEXTURE_2D, 0, GLColor::yellow);
1186 verifyAttachment2DColor(1, mTextures[1], GL_TEXTURE_2D, 0, GLColor::green);
1187 EXPECT_GL_NO_ERROR();
1188 }
1189
1190 ANGLE_INSTANTIATE_TEST(DrawBuffersTest,
1191 ANGLE_ALL_TEST_PLATFORMS_ES2,
1192 ANGLE_ALL_TEST_PLATFORMS_ES3,
1193 WithNoTransformFeedback(ES2_VULKAN()));
1194
1195 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DrawBuffersWebGL2Test);
1196 ANGLE_INSTANTIATE_TEST_ES3(DrawBuffersWebGL2Test);
1197
1198 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DrawBuffersTestES3);
1199 ANGLE_INSTANTIATE_TEST_ES3(DrawBuffersTestES3);
1200
1201 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ColorMaskForDrawBuffersTest);
1202 ANGLE_INSTANTIATE_TEST_ES3(ColorMaskForDrawBuffersTest);
1203