• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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