xref: /aosp_15_r20/external/angle/src/tests/gl_tests/DrawBuffersTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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     glBindTexture(GL_TEXTURE_2D, mTextures[0]);
266     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, mTextures[0], 0);
267 
268     bool flags[8] = {false, true};
269 
270     GLuint program;
271     setupMRTProgram(flags, &program);
272 
273     const GLenum bufs[] = {GL_NONE, GL_COLOR_ATTACHMENT1};
274     setDrawBuffers(2, bufs);
275     drawQuad(program, positionAttrib(), 0.5);
276 
277     verifyAttachment2D(1, mTextures[0], GL_TEXTURE_2D, 0);
278 
279     glDeleteProgram(program);
280 }
281 
282 // Test that blend works with gaps
TEST_P(DrawBuffersTest,BlendWithGaps)283 TEST_P(DrawBuffersTest, BlendWithGaps)
284 {
285     ANGLE_SKIP_TEST_IF(!setupTest());
286 
287     // http://anglebug.com/42263715
288     ANGLE_SKIP_TEST_IF(IsMac() && IsIntel() && IsDesktopOpenGL());
289 
290     glBindTexture(GL_TEXTURE_2D, mTextures[0]);
291     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, mTextures[0], 0);
292 
293     ASSERT_GL_NO_ERROR();
294 
295     bool flags[8] = {false, true};
296 
297     GLuint program;
298     setupMRTProgram(flags, &program);
299 
300     const GLenum bufs[] = {GL_NONE, GL_COLOR_ATTACHMENT1};
301     setDrawBuffers(2, bufs);
302 
303     // Draws green into attachment 1
304     drawQuad(program, positionAttrib(), 0.5);
305     verifyAttachment2D(1, mTextures[0], GL_TEXTURE_2D, 0);
306     ASSERT_GL_NO_ERROR();
307 
308     // Clear with red
309     glClearColor(1.0, 0.0, 0.0, 1.0);
310     glClear(GL_COLOR_BUFFER_BIT);
311     verifyAttachment2DColor(1, mTextures[0], GL_TEXTURE_2D, 0, GLColor(255u, 0, 0, 255u));
312 
313     // Draw green into attachment 1 again but with blending, expecting yellow
314     glEnable(GL_BLEND);
315     glBlendFunc(GL_ONE, GL_ONE);
316     drawQuad(program, positionAttrib(), 0.5);
317     verifyAttachment2DColor(1, mTextures[0], GL_TEXTURE_2D, 0, GLColor(255u, 255u, 0, 255u));
318     ASSERT_GL_NO_ERROR();
319 
320     glDeleteProgram(program);
321 }
322 
323 // Test that clear works with gaps
TEST_P(DrawBuffersTest,ClearWithGaps)324 TEST_P(DrawBuffersTest, ClearWithGaps)
325 {
326     ANGLE_SKIP_TEST_IF(!setupTest());
327 
328     glGetIntegerv(GL_MAX_DRAW_BUFFERS, &mMaxDrawBuffers);
329     ASSERT_GE(mMaxDrawBuffers, 4);
330 
331     glBindTexture(GL_TEXTURE_2D, mTextures[0]);
332     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
333 
334     glBindTexture(GL_TEXTURE_2D, mTextures[1]);
335     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, mTextures[1], 0);
336 
337     const GLenum bufs[] = {GL_COLOR_ATTACHMENT0, GL_NONE, GL_NONE, GL_COLOR_ATTACHMENT3};
338 
339     bool flags[8] = {true, false, false, true};
340     GLuint program;
341     setupMRTProgram(flags, &program);
342 
343     setDrawBuffers(4, bufs);
344 
345     glClearColor(1.0f, 1.0f, 0.0f, 1.0f);
346     glClear(GL_COLOR_BUFFER_BIT);
347 
348     // A bogus draw to make sure clears are done with a render pass in the Vulkan backend.
349     glEnable(GL_BLEND);
350     glBlendFunc(GL_ZERO, GL_ONE);
351     drawQuad(program, positionAttrib(), 0.5);
352     EXPECT_GL_NO_ERROR();
353 
354     verifyAttachment2DColor(0, mTextures[0], GL_TEXTURE_2D, 0, GLColor::yellow);
355     verifyAttachment2DColor(3, mTextures[1], GL_TEXTURE_2D, 0, GLColor::yellow);
356 
357     EXPECT_GL_NO_ERROR();
358 }
359 
360 // Test that mid-render pass clear works with gaps
TEST_P(DrawBuffersTest,MidRenderPassClearWithGaps)361 TEST_P(DrawBuffersTest, MidRenderPassClearWithGaps)
362 {
363     ANGLE_SKIP_TEST_IF(!setupTest());
364 
365     glGetIntegerv(GL_MAX_DRAW_BUFFERS, &mMaxDrawBuffers);
366     ASSERT_GE(mMaxDrawBuffers, 4);
367 
368     glBindTexture(GL_TEXTURE_2D, mTextures[0]);
369     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
370 
371     glBindTexture(GL_TEXTURE_2D, mTextures[1]);
372     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, mTextures[1], 0);
373 
374     const GLenum bufs[] = {GL_COLOR_ATTACHMENT0, GL_NONE, GL_NONE, GL_COLOR_ATTACHMENT3};
375 
376     bool flags[8] = {true, false, false, true};
377     GLuint program;
378     setupMRTProgram(flags, &program);
379 
380     setDrawBuffers(4, bufs);
381 
382     drawQuad(program, positionAttrib(), 0.5);
383 
384     glClearColor(1.0f, 1.0f, 0.0f, 1.0f);
385     glClear(GL_COLOR_BUFFER_BIT);
386 
387     // A bogus draw to make sure clears are done with a render pass in the Vulkan backend.
388     glEnable(GL_BLEND);
389     glBlendFunc(GL_ZERO, GL_ONE);
390     drawQuad(program, positionAttrib(), 0.5);
391     EXPECT_GL_NO_ERROR();
392 
393     verifyAttachment2DColor(0, mTextures[0], GL_TEXTURE_2D, 0, GLColor::yellow);
394     verifyAttachment2DColor(3, mTextures[1], GL_TEXTURE_2D, 0, GLColor::yellow);
395 
396     EXPECT_GL_NO_ERROR();
397 }
398 
399 // Test that mid-render pass clear works with gaps.  Uses RGB format.
TEST_P(DrawBuffersTest,MidRenderPassClearWithGapsRGB)400 TEST_P(DrawBuffersTest, MidRenderPassClearWithGapsRGB)
401 {
402     ANGLE_SKIP_TEST_IF(!setupTest());
403 
404     glGetIntegerv(GL_MAX_DRAW_BUFFERS, &mMaxDrawBuffers);
405     ASSERT_GE(mMaxDrawBuffers, 4);
406 
407     GLTexture textures[2];
408 
409     glBindTexture(GL_TEXTURE_2D, textures[0]);
410     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB,
411                  GL_UNSIGNED_BYTE, nullptr);
412     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0], 0);
413 
414     glBindTexture(GL_TEXTURE_2D, textures[1]);
415     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB,
416                  GL_UNSIGNED_BYTE, nullptr);
417     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, textures[1], 0);
418 
419     const GLenum bufs[] = {GL_COLOR_ATTACHMENT0, GL_NONE, GL_NONE, GL_COLOR_ATTACHMENT3};
420 
421     bool flags[8] = {true, false, false, true};
422     GLuint program;
423     setupMRTProgram(flags, &program);
424 
425     setDrawBuffers(4, bufs);
426 
427     drawQuad(program, positionAttrib(), 0.5);
428 
429     glClearColor(1.0f, 1.0f, 0.0f, 1.0f);
430     glClear(GL_COLOR_BUFFER_BIT);
431 
432     // A bogus draw to make sure clears are done with a render pass in the Vulkan backend.
433     glEnable(GL_BLEND);
434     glBlendFunc(GL_ZERO, GL_ONE);
435     drawQuad(program, positionAttrib(), 0.5);
436     EXPECT_GL_NO_ERROR();
437 
438     verifyAttachment2DColor(0, textures[0], GL_TEXTURE_2D, 0, GLColor::yellow);
439     verifyAttachment2DColor(3, textures[1], GL_TEXTURE_2D, 0, GLColor::yellow);
440 
441     EXPECT_GL_NO_ERROR();
442 }
443 
444 // Test that a masked draw and a mid-render pass clear works with gaps.
TEST_P(DrawBuffersTest,MaskedDrawMidRPClearWithGaps)445 TEST_P(DrawBuffersTest, MaskedDrawMidRPClearWithGaps)
446 {
447     ANGLE_SKIP_TEST_IF(!setupTest());
448 
449     glGetIntegerv(GL_MAX_DRAW_BUFFERS, &mMaxDrawBuffers);
450     ASSERT_GE(mMaxDrawBuffers, 4);
451 
452     glBindTexture(GL_TEXTURE_2D, mTextures[0]);
453     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
454 
455     glBindTexture(GL_TEXTURE_2D, mTextures[1]);
456     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, mTextures[1], 0);
457 
458     // Mask out attachment 3, so we only draw to attachment 1.
459     GLenum bufs[] = {GL_COLOR_ATTACHMENT0, GL_NONE, GL_NONE, GL_NONE};
460     bool flags[8] = {true, false, false, false};
461     GLuint program;
462     setupMRTProgram(flags, &program);
463 
464     setDrawBuffers(4, bufs);
465 
466     drawQuad(program, positionAttrib(), 0.5);
467 
468     // Re-enable attachment 3, so we clear both attachment 1 and 3.
469     bufs[3] = GL_COLOR_ATTACHMENT3;
470     setDrawBuffers(4, bufs);
471     flags[3] = true;
472     setupMRTProgram(flags, &program);
473 
474     glClearColor(1.0f, 1.0f, 0.0f, 1.0f);
475     glClear(GL_COLOR_BUFFER_BIT);
476 
477     // A bogus draw to make sure clears are done with a render pass in the Vulkan backend.
478     glEnable(GL_BLEND);
479     glBlendFunc(GL_ZERO, GL_ONE);
480     drawQuad(program, positionAttrib(), 0.5);
481     EXPECT_GL_NO_ERROR();
482 
483     verifyAttachment2DColor(0, mTextures[0], GL_TEXTURE_2D, 0, GLColor::yellow);
484     verifyAttachment2DColor(3, mTextures[1], GL_TEXTURE_2D, 0, GLColor::yellow);
485 
486     EXPECT_GL_NO_ERROR();
487 }
488 
489 // Test that a masked draw and a mid-render pass clear works with gaps.  Uses RGB format.
TEST_P(DrawBuffersTest,MaskedDrawMidRPClearWithGapsRGB)490 TEST_P(DrawBuffersTest, MaskedDrawMidRPClearWithGapsRGB)
491 {
492     ANGLE_SKIP_TEST_IF(!setupTest());
493 
494     glGetIntegerv(GL_MAX_DRAW_BUFFERS, &mMaxDrawBuffers);
495     ASSERT_GE(mMaxDrawBuffers, 4);
496 
497     GLTexture textures[2];
498 
499     glBindTexture(GL_TEXTURE_2D, textures[0]);
500     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB,
501                  GL_UNSIGNED_BYTE, nullptr);
502     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0], 0);
503 
504     glBindTexture(GL_TEXTURE_2D, textures[1]);
505     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, getWindowWidth(), getWindowHeight(), 0, GL_RGB,
506                  GL_UNSIGNED_BYTE, nullptr);
507     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, textures[1], 0);
508 
509     // Mask out attachment 3, so we only draw to attachment 1.
510     GLenum bufs[] = {GL_COLOR_ATTACHMENT0, GL_NONE, GL_NONE, GL_NONE};
511     bool flags[8] = {true, false, false, false};
512     GLuint program;
513     setupMRTProgram(flags, &program);
514 
515     setDrawBuffers(4, bufs);
516 
517     drawQuad(program, positionAttrib(), 0.5);
518 
519     // Re-enable attachment 3, so we clear both attachment 1 and 3.
520     bufs[3] = GL_COLOR_ATTACHMENT3;
521     setDrawBuffers(4, bufs);
522     flags[3] = true;
523     setupMRTProgram(flags, &program);
524 
525     glClearColor(1.0f, 1.0f, 0.0f, 1.0f);
526     glClear(GL_COLOR_BUFFER_BIT);
527 
528     // A bogus draw to make sure clears are done with a render pass in the Vulkan backend.
529     glEnable(GL_BLEND);
530     glBlendFunc(GL_ZERO, GL_ONE);
531     drawQuad(program, positionAttrib(), 0.5);
532     EXPECT_GL_NO_ERROR();
533 
534     verifyAttachment2DColor(0, textures[0], GL_TEXTURE_2D, 0, GLColor::yellow);
535     verifyAttachment2DColor(3, textures[1], GL_TEXTURE_2D, 0, GLColor::yellow);
536 
537     EXPECT_GL_NO_ERROR();
538 }
539 
TEST_P(DrawBuffersTest,FirstAndLast)540 TEST_P(DrawBuffersTest, FirstAndLast)
541 {
542     ANGLE_SKIP_TEST_IF(!setupTest());
543 
544     glBindTexture(GL_TEXTURE_2D, mTextures[0]);
545     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
546 
547     glBindTexture(GL_TEXTURE_2D, mTextures[1]);
548     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, mTextures[1], 0);
549 
550     bool flags[8] = {true, false, false, true};
551 
552     GLuint program;
553     setupMRTProgram(flags, &program);
554 
555     const GLenum bufs[] = {GL_COLOR_ATTACHMENT0, GL_NONE, GL_NONE, GL_COLOR_ATTACHMENT3};
556 
557     setDrawBuffers(4, bufs);
558     drawQuad(program, positionAttrib(), 0.5);
559 
560     verifyAttachment2D(0, mTextures[0], GL_TEXTURE_2D, 0);
561     verifyAttachment2D(3, mTextures[1], GL_TEXTURE_2D, 0);
562 
563     EXPECT_GL_NO_ERROR();
564 
565     glDeleteProgram(program);
566 }
567 
TEST_P(DrawBuffersTest,FirstHalfNULL)568 TEST_P(DrawBuffersTest, FirstHalfNULL)
569 {
570     ANGLE_SKIP_TEST_IF(!setupTest());
571 
572     bool flags[8]  = {false};
573     GLenum bufs[8] = {GL_NONE};
574 
575     ASSERT_GT(mMaxDrawBuffers, 0);
576     ASSERT_LE(mMaxDrawBuffers, 8);
577     GLuint halfMaxDrawBuffers = static_cast<GLuint>(mMaxDrawBuffers) / 2;
578 
579     for (GLuint texIndex = 0; texIndex < halfMaxDrawBuffers; texIndex++)
580     {
581         glBindTexture(GL_TEXTURE_2D, mTextures[texIndex]);
582         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + halfMaxDrawBuffers + texIndex,
583                                GL_TEXTURE_2D, mTextures[texIndex], 0);
584         flags[texIndex + halfMaxDrawBuffers] = true;
585         bufs[texIndex + halfMaxDrawBuffers]  = GL_COLOR_ATTACHMENT0 + halfMaxDrawBuffers + texIndex;
586     }
587 
588     GLuint program;
589     setupMRTProgram(flags, &program);
590 
591     setDrawBuffers(mMaxDrawBuffers, bufs);
592     drawQuad(program, positionAttrib(), 0.5);
593 
594     for (GLuint texIndex = 0; texIndex < halfMaxDrawBuffers; texIndex++)
595     {
596         verifyAttachment2D(texIndex + halfMaxDrawBuffers, mTextures[texIndex], GL_TEXTURE_2D, 0);
597     }
598 
599     EXPECT_GL_NO_ERROR();
600 
601     glDeleteProgram(program);
602 }
603 
604 // Test that non-zero draw buffers can be queried on the default framebuffer
TEST_P(DrawBuffersTest,DefaultFramebufferDrawBufferQuery)605 TEST_P(DrawBuffersTest, DefaultFramebufferDrawBufferQuery)
606 {
607     ANGLE_SKIP_TEST_IF(!setupTest());
608 
609     glBindFramebuffer(GL_FRAMEBUFFER, 0);
610 
611     GLint drawbuffer = 0;
612     glGetIntegerv(GL_DRAW_BUFFER1, &drawbuffer);
613     EXPECT_GL_NO_ERROR();
614 
615     EXPECT_EQ(GL_NONE, drawbuffer);
616 }
617 
618 // Test that drawing with all color buffers disabled works.
TEST_P(DrawBuffersTest,None)619 TEST_P(DrawBuffersTest, None)
620 {
621     ANGLE_SKIP_TEST_IF(!setupTest());
622 
623     bool flags[8]  = {false};
624     GLenum bufs[8] = {GL_NONE};
625     GLTexture textures[8];
626 
627     ASSERT_GT(mMaxDrawBuffers, 0);
628     ASSERT_LE(mMaxDrawBuffers, 8);
629     for (GLint texIndex = 0; texIndex < mMaxDrawBuffers; ++texIndex)
630     {
631         glBindTexture(GL_TEXTURE_2D, textures[texIndex]);
632         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
633                      GL_UNSIGNED_BYTE, nullptr);
634         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + texIndex, GL_TEXTURE_2D,
635                                textures[texIndex], 0);
636         flags[texIndex] = true;
637         bufs[texIndex]  = GL_COLOR_ATTACHMENT0 + texIndex;
638     }
639 
640     GLuint program;
641     setupMRTProgram(flags, &program);
642 
643     setDrawBuffers(mMaxDrawBuffers, bufs);
644     glClearColor(0.5, 0.5, 0.5, 1.0);
645     glClear(GL_COLOR_BUFFER_BIT);
646 
647     for (GLint texIndex = 0; texIndex < mMaxDrawBuffers; ++texIndex)
648     {
649         bufs[texIndex] = GL_NONE;
650     }
651 
652     setDrawBuffers(mMaxDrawBuffers, bufs);
653     drawQuad(program, positionAttrib(), 0.5);
654 
655     ASSERT_GL_NO_ERROR();
656 
657     for (GLint texIndex = 0; texIndex < mMaxDrawBuffers; ++texIndex)
658     {
659         glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
660                                textures[texIndex], 0);
661         EXPECT_PIXEL_NEAR(getWindowWidth() / 2, getWindowHeight() / 2, 127, 127, 127, 255, 1);
662     }
663 
664     glDeleteProgram(program);
665 }
666 
667 // Test that drawing with a color buffer disabled and a depth buffer enabled works.
TEST_P(DrawBuffersTest,NoneWithDepth)668 TEST_P(DrawBuffersTest, NoneWithDepth)
669 {
670     ANGLE_SKIP_TEST_IF(!setupTest());
671 
672     bool flags[8]  = {true, false, false, false, false, false, false, false};
673     GLenum bufs[8] = {
674         GL_COLOR_ATTACHMENT0, GL_NONE, GL_NONE, GL_NONE, GL_NONE, GL_NONE, GL_NONE, GL_NONE};
675 
676     GLTexture texture;
677     glBindTexture(GL_TEXTURE_2D, texture);
678     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
679                  GL_UNSIGNED_BYTE, nullptr);
680     glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
681     glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
682 
683     GLRenderbuffer rb;
684     glBindRenderbuffer(GL_RENDERBUFFER, rb);
685     glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, getWindowWidth(),
686                           getWindowHeight());
687     glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rb);
688 
689     EXPECT_GL_NO_ERROR();
690     EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_DRAW_FRAMEBUFFER);
691 
692     GLuint program;
693     setupMRTProgram(flags, &program);
694 
695     ASSERT_GT(mMaxDrawBuffers, 0);
696     ASSERT_LE(mMaxDrawBuffers, 8);
697     setDrawBuffers(mMaxDrawBuffers, bufs);
698 
699     glClearColor(0.5, 0.5, 0.5, 1.0);
700     glClearDepthf(0.0);
701     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
702     EXPECT_PIXEL_NEAR(getWindowWidth() / 2, getWindowHeight() / 2, 127, 127, 127, 255, 1);
703 
704     // Color buffer must remain untouched, depth buffer must be set to 1.0
705     bufs[0] = GL_NONE;
706     setDrawBuffers(mMaxDrawBuffers, bufs);
707     glEnable(GL_DEPTH_TEST);
708     glDepthFunc(GL_ALWAYS);
709     drawQuad(program, positionAttrib(), 1.0);
710     EXPECT_GL_NO_ERROR();
711     EXPECT_PIXEL_NEAR(getWindowWidth() / 2, getWindowHeight() / 2, 127, 127, 127, 255, 1);
712 
713     // Draw with the color buffer and depth test enabled.
714     // Depth test must fail and the color buffer must remain unchanged.
715     bufs[0] = GL_COLOR_ATTACHMENT0;
716     setDrawBuffers(mMaxDrawBuffers, bufs);
717     glDepthFunc(GL_LESS);
718     drawQuad(program, positionAttrib(), 1.0);
719     EXPECT_PIXEL_NEAR(getWindowWidth() / 2, getWindowHeight() / 2, 127, 127, 127, 255, 1);
720 
721     // Draw with another Z value.
722     // Depth test must pass and the color buffer must be updated.
723     drawQuad(program, positionAttrib(), 0.0);
724     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::red);
725 
726     glDeleteProgram(program);
727 }
728 
729 // Test that drawing with a color buffer disabled and a stencil buffer enabled works.
TEST_P(DrawBuffersTest,NoneWithStencil)730 TEST_P(DrawBuffersTest, NoneWithStencil)
731 {
732     ANGLE_SKIP_TEST_IF(!setupTest());
733 
734     bool flags[8]  = {true, false, false, false, false, false, false, false};
735     GLenum bufs[8] = {
736         GL_COLOR_ATTACHMENT0, GL_NONE, GL_NONE, GL_NONE, GL_NONE, GL_NONE, GL_NONE, GL_NONE};
737 
738     GLTexture texture;
739     glBindTexture(GL_TEXTURE_2D, texture);
740     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
741                  GL_UNSIGNED_BYTE, nullptr);
742     glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
743     glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
744 
745     GLRenderbuffer rb;
746     glBindRenderbuffer(GL_RENDERBUFFER, rb);
747     glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, getWindowWidth(), getWindowHeight());
748     glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rb);
749 
750     EXPECT_GL_NO_ERROR();
751     EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_DRAW_FRAMEBUFFER);
752 
753     GLuint program;
754     setupMRTProgram(flags, &program);
755 
756     ASSERT_GT(mMaxDrawBuffers, 0);
757     ASSERT_LE(mMaxDrawBuffers, 8);
758     setDrawBuffers(mMaxDrawBuffers, bufs);
759 
760     glClearColor(0.5, 0.5, 0.5, 1.0);
761     glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
762     EXPECT_PIXEL_NEAR(getWindowWidth() / 2, getWindowHeight() / 2, 127, 127, 127, 255, 1);
763 
764     // Color buffer must remain untouched, stencil test must pass and stencil buffer must be
765     // incremented to 1.
766     bufs[0] = GL_NONE;
767     setDrawBuffers(mMaxDrawBuffers, bufs);
768     glEnable(GL_STENCIL_TEST);
769     glStencilOp(GL_KEEP, GL_INCR, GL_INCR);
770     drawQuad(program, positionAttrib(), 1.0);
771     EXPECT_GL_NO_ERROR();
772     EXPECT_PIXEL_NEAR(getWindowWidth() / 2, getWindowHeight() / 2, 127, 127, 127, 255, 1);
773 
774     // Draw with the color buffer enabled and stencil test expecting 0.
775     // Stencil test must fail, and both the color and the stencil buffers must remain unchanged.
776     bufs[0] = GL_COLOR_ATTACHMENT0;
777     setDrawBuffers(mMaxDrawBuffers, bufs);
778     glStencilFunc(GL_EQUAL, 0, 255);
779     drawQuad(program, positionAttrib(), 1.0);
780     EXPECT_PIXEL_NEAR(getWindowWidth() / 2, getWindowHeight() / 2, 127, 127, 127, 255, 1);
781 
782     // Draw with stencil ref value matching the stored stencil buffer value.
783     // Stencil test must pass and the color buffer must be updated.
784     glStencilFunc(GL_EQUAL, 1, 255);
785     drawQuad(program, positionAttrib(), 1.0);
786     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::red);
787 
788     glDeleteProgram(program);
789 }
790 
791 // Test that draws to every buffer and verifies that every buffer was drawn to.
TEST_P(DrawBuffersTest,AllRGBA8)792 TEST_P(DrawBuffersTest, AllRGBA8)
793 {
794     ANGLE_SKIP_TEST_IF(!setupTest());
795 
796     bool flags[8]  = {false};
797     GLenum bufs[8] = {GL_NONE};
798     GLTexture textures[8];
799 
800     ASSERT_GT(mMaxDrawBuffers, 0);
801     ASSERT_LE(mMaxDrawBuffers, 8);
802     for (GLint texIndex = 0; texIndex < mMaxDrawBuffers; ++texIndex)
803     {
804         glBindTexture(GL_TEXTURE_2D, textures[texIndex]);
805         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,
806                      GL_UNSIGNED_BYTE, nullptr);
807         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
808         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
809         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + texIndex, GL_TEXTURE_2D,
810                                textures[texIndex], 0);
811         flags[texIndex] = true;
812         bufs[texIndex]  = GL_COLOR_ATTACHMENT0 + texIndex;
813     }
814 
815     GLuint program;
816     setupMRTProgram(flags, &program);
817 
818     setDrawBuffers(mMaxDrawBuffers, bufs);
819     drawQuad(program, positionAttrib(), 0.5);
820 
821     for (GLint texIndex = 0; texIndex < mMaxDrawBuffers; ++texIndex)
822     {
823         verifyAttachment2D(texIndex, textures[texIndex], GL_TEXTURE_2D, 0);
824     }
825 
826     EXPECT_GL_NO_ERROR();
827 
828     glDeleteProgram(program);
829 }
830 // Same as above but adds a state change from a program with different masks after a clear.
TEST_P(DrawBuffersWebGL2Test,TwoProgramsWithDifferentOutputsAndClear)831 TEST_P(DrawBuffersWebGL2Test, TwoProgramsWithDifferentOutputsAndClear)
832 {
833     // TODO(http://anglebug.com/42261569): Broken on the GL back-end.
834     ANGLE_SKIP_TEST_IF(IsOpenGL());
835 
836     ANGLE_SKIP_TEST_IF(!setupTest());
837 
838     glGetIntegerv(GL_MAX_DRAW_BUFFERS, &mMaxDrawBuffers);
839     ASSERT_GE(mMaxDrawBuffers, 4);
840 
841     bool flags[8]      = {false};
842     GLenum someBufs[4] = {GL_NONE};
843     GLenum allBufs[4]  = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2,
844                           GL_COLOR_ATTACHMENT3};
845 
846     constexpr GLuint kMaxBuffers     = 4;
847     constexpr GLuint kHalfMaxBuffers = 2;
848 
849     // Enable all draw buffers.
850     for (GLuint texIndex = 0; texIndex < kMaxBuffers; texIndex++)
851     {
852         glBindTexture(GL_TEXTURE_2D, mTextures[texIndex]);
853         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + texIndex, GL_TEXTURE_2D,
854                                mTextures[texIndex], 0);
855         someBufs[texIndex] =
856             texIndex >= kHalfMaxBuffers ? GL_COLOR_ATTACHMENT0 + texIndex : GL_NONE;
857 
858         // Mask out the first two buffers.
859         flags[texIndex] = texIndex >= kHalfMaxBuffers;
860     }
861 
862     GLuint program;
863     setupMRTProgram(flags, &program);
864 
865     // Now set up a second simple program that draws to FragColor. Should be broadcast.
866     ANGLE_GL_PROGRAM(simpleProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
867 
868     // Draw with simple program.
869     drawQuad(simpleProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
870     ASSERT_GL_NO_ERROR();
871 
872     // Clear draw buffers.
873     setDrawBuffers(kMaxBuffers, someBufs);
874     glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
875     glClear(GL_COLOR_BUFFER_BIT);
876 
877     ASSERT_GL_NO_ERROR();
878 
879     // Verify first is drawn red, second is untouched, and last two are cleared green.
880     verifyAttachment2DColor(0, mTextures[0], GL_TEXTURE_2D, 0, GLColor::red);
881     verifyAttachment2DColor(1, mTextures[1], GL_TEXTURE_2D, 0, GLColor::transparentBlack);
882     verifyAttachment2DColor(2, mTextures[2], GL_TEXTURE_2D, 0, GLColor::green);
883     verifyAttachment2DColor(3, mTextures[3], GL_TEXTURE_2D, 0, GLColor::green);
884 
885     // Draw with MRT program.
886     setDrawBuffers(kMaxBuffers, someBufs);
887     drawQuad(program, positionAttrib(), 0.5, 1.0f, true);
888     ASSERT_GL_NO_ERROR();
889 
890     // Only the last two attachments should be updated.
891     verifyAttachment2DColor(0, mTextures[0], GL_TEXTURE_2D, 0, GLColor::red);
892     verifyAttachment2DColor(1, mTextures[1], GL_TEXTURE_2D, 0, GLColor::transparentBlack);
893     verifyAttachment2D(2, mTextures[2], GL_TEXTURE_2D, 0);
894     verifyAttachment2D(3, mTextures[3], GL_TEXTURE_2D, 0);
895 
896     // Active draw buffers with no fragment output is not allowed.
897     setDrawBuffers(kMaxBuffers, allBufs);
898     drawQuad(program, positionAttrib(), 0.5, 1.0f, true);
899     ASSERT_GL_ERROR(GL_INVALID_OPERATION);
900     // Exception: when RASTERIZER_DISCARD is enabled.
901     glEnable(GL_RASTERIZER_DISCARD);
902     drawQuad(program, positionAttrib(), 0.5, 1.0f, true);
903     ASSERT_GL_NO_ERROR();
904     glDisable(GL_RASTERIZER_DISCARD);
905     // Exception: when all 4 channels of color mask are set to false.
906     glColorMask(false, false, false, false);
907     drawQuad(program, positionAttrib(), 0.5, 1.0f, true);
908     ASSERT_GL_NO_ERROR();
909     glColorMask(false, true, false, false);
910     drawQuad(program, positionAttrib(), 0.5, 1.0f, true);
911     ASSERT_GL_ERROR(GL_INVALID_OPERATION);
912     glColorMask(true, true, true, true);
913     drawQuad(program, positionAttrib(), 0.5, 1.0f, true);
914     ASSERT_GL_ERROR(GL_INVALID_OPERATION);
915 
916     // Clear again. All attachments should be cleared.
917     glClear(GL_COLOR_BUFFER_BIT);
918     verifyAttachment2DColor(0, mTextures[0], GL_TEXTURE_2D, 0, GLColor::green);
919     verifyAttachment2DColor(1, mTextures[1], GL_TEXTURE_2D, 0, GLColor::green);
920     verifyAttachment2DColor(2, mTextures[2], GL_TEXTURE_2D, 0, GLColor::green);
921     verifyAttachment2DColor(3, mTextures[3], GL_TEXTURE_2D, 0, GLColor::green);
922 
923     glDeleteProgram(program);
924 }
925 
926 // Test clear with gaps in draw buffers, originally show up as
927 // webgl_conformance_vulkan_passthrough_tests conformance/extensions/webgl-draw-buffers.html
928 // failure. This is added for ease of debugging.
TEST_P(DrawBuffersWebGL2Test,Clear)929 TEST_P(DrawBuffersWebGL2Test, Clear)
930 {
931     ANGLE_SKIP_TEST_IF(!setupTest());
932 
933     constexpr GLint kMaxBuffers = 4;
934 
935     glGetIntegerv(GL_MAX_DRAW_BUFFERS, &mMaxDrawBuffers);
936     ASSERT_GE(mMaxDrawBuffers, kMaxBuffers);
937 
938     GLenum drawBufs[kMaxBuffers] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
939                                     GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3};
940 
941     // Enable all draw buffers.
942     for (GLuint texIndex = 0; texIndex < kMaxBuffers; texIndex++)
943     {
944         glBindTexture(GL_TEXTURE_2D, mTextures[texIndex]);
945         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + texIndex, GL_TEXTURE_2D,
946                                mTextures[texIndex], 0);
947     }
948 
949     // Clear with all draw buffers.
950     setDrawBuffers(kMaxBuffers, drawBufs);
951     glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
952     glClear(GL_COLOR_BUFFER_BIT);
953 
954     // Clear with first half none draw buffers.
955     drawBufs[0] = GL_NONE;
956     drawBufs[1] = GL_NONE;
957     setDrawBuffers(kMaxBuffers, drawBufs);
958     glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
959     glClear(GL_COLOR_BUFFER_BIT);
960 
961     ASSERT_GL_NO_ERROR();
962 
963     // Verify first is drawn red, second is untouched, and last two are cleared green.
964     verifyAttachment2DColor(0, mTextures[0], GL_TEXTURE_2D, 0, GLColor::red);
965     verifyAttachment2DColor(1, mTextures[1], GL_TEXTURE_2D, 0, GLColor::red);
966     verifyAttachment2DColor(2, mTextures[2], GL_TEXTURE_2D, 0, GLColor::green);
967     verifyAttachment2DColor(3, mTextures[3], GL_TEXTURE_2D, 0, GLColor::green);
968 }
969 
TEST_P(DrawBuffersTest,UnwrittenOutputVariablesShouldNotCrash)970 TEST_P(DrawBuffersTest, UnwrittenOutputVariablesShouldNotCrash)
971 {
972     ANGLE_SKIP_TEST_IF(!setupTest());
973 
974     // Bind two render targets but use a shader which writes only to the first one.
975     glBindTexture(GL_TEXTURE_2D, mTextures[0]);
976     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
977 
978     glBindTexture(GL_TEXTURE_2D, mTextures[1]);
979     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, mTextures[1], 0);
980 
981     bool flags[8] = {true, false};
982 
983     GLuint program;
984     setupMRTProgram(flags, &program);
985 
986     const GLenum bufs[] = {
987         GL_COLOR_ATTACHMENT0,
988         GL_COLOR_ATTACHMENT1,
989         GL_NONE,
990         GL_NONE,
991     };
992 
993     setDrawBuffers(4, bufs);
994 
995     // This call should not crash when we dynamically generate the HLSL code.
996     drawQuad(program, positionAttrib(), 0.5);
997 
998     verifyAttachment2D(0, mTextures[0], GL_TEXTURE_2D, 0);
999 
1000     EXPECT_GL_NO_ERROR();
1001 
1002     glDeleteProgram(program);
1003 }
1004 
TEST_P(DrawBuffersTest,BroadcastGLFragColor)1005 TEST_P(DrawBuffersTest, BroadcastGLFragColor)
1006 {
1007     // Broadcast is not supported on GLES 3.0.
1008     ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);
1009     ANGLE_SKIP_TEST_IF(!setupTest());
1010 
1011     // Bind two render targets. gl_FragColor should be broadcast to both.
1012     glBindTexture(GL_TEXTURE_2D, mTextures[0]);
1013     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);
1014 
1015     glBindTexture(GL_TEXTURE_2D, mTextures[1]);
1016     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, mTextures[1], 0);
1017 
1018     const GLenum bufs[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
1019 
1020     constexpr char kFS[] =
1021         "#extension GL_EXT_draw_buffers : enable\n"
1022         "precision highp float;\n"
1023         "uniform float u_zero;\n"
1024         "void main()\n"
1025         "{\n"
1026         "    gl_FragColor = vec4(1, 0, 0, 1);\n"
1027         "    if (u_zero < 1.0)\n"
1028         "    {\n"
1029         "        return;\n"
1030         "    }\n"
1031         "}\n";
1032 
1033     GLuint program = CompileProgram(essl1_shaders::vs::Simple(), kFS);
1034     if (program == 0)
1035     {
1036         FAIL() << "shader compilation failed.";
1037     }
1038 
1039     setDrawBuffers(2, bufs);
1040     drawQuad(program, essl1_shaders::PositionAttrib(), 0.5);
1041 
1042     verifyAttachment2D(0, mTextures[0], GL_TEXTURE_2D, 0);
1043     verifyAttachment2D(0, mTextures[1], GL_TEXTURE_2D, 0);
1044 
1045     EXPECT_GL_NO_ERROR();
1046 
1047     glDeleteProgram(program);
1048 }
1049 
1050 // Test that binding multiple layers of a 3D texture works correctly.
1051 // This is the same as DrawBuffersTestES3.3DTextures but is used for GL_OES_texture_3D extension
1052 // on GLES 2.0 instead.
1053 TEST_P(DrawBuffersTest, 3DTexturesOES)
1054 {
1055     ANGLE_SKIP_TEST_IF(!setupTest());
1056     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_3D"));
1057 
1058     GLTexture texture;
1059     glBindTexture(GL_TEXTURE_3D, texture);
1060     glTexImage3DOES(GL_TEXTURE_3D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(),
1061                     getWindowWidth(), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1062 
1063     glFramebufferTexture3DOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, texture, 0, 0);
1064     glFramebufferTexture3DOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_3D, texture, 0, 1);
1065     glFramebufferTexture3DOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_3D, texture, 0, 2);
1066     glFramebufferTexture3DOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_3D, texture, 0, 3);
1067 
1068     bool flags[8] = {true, true, true, true, false};
1069 
1070     GLuint program;
1071     setupMRTProgram(flags, &program);
1072 
1073     const GLenum bufs[] = {
1074         GL_COLOR_ATTACHMENT0,
1075         GL_COLOR_ATTACHMENT1,
1076         GL_COLOR_ATTACHMENT2,
1077         GL_COLOR_ATTACHMENT3,
1078     };
1079 
1080     setDrawBuffers(4, bufs);
1081     drawQuad(program, positionAttrib(), 0.5);
1082 
1083     verifyAttachment3DOES(0, texture, 0, 0);
1084     verifyAttachment3DOES(1, texture, 0, 1);
1085     verifyAttachment3DOES(2, texture, 0, 2);
1086     verifyAttachment3DOES(3, texture, 0, 3);
1087 
1088     EXPECT_GL_NO_ERROR();
1089 
1090     glDeleteProgram(program);
1091 }
1092 
1093 class DrawBuffersTestES3 : public DrawBuffersTest
1094 {};
1095 
1096 // Test that binding multiple layers of a 3D texture works correctly
1097 TEST_P(DrawBuffersTestES3, 3DTextures)
1098 {
1099     ANGLE_SKIP_TEST_IF(!setupTest());
1100 
1101     GLTexture texture;
1102     glBindTexture(GL_TEXTURE_3D, texture);
1103     glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), getWindowWidth(),
1104                  0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1105 
1106     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, 0);
1107     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture, 0, 1);
1108     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, texture, 0, 2);
1109     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, texture, 0, 3);
1110 
1111     bool flags[8] = {true, true, true, true, false};
1112 
1113     GLuint program;
1114     setupMRTProgram(flags, &program);
1115 
1116     const GLenum bufs[] = {
1117         GL_COLOR_ATTACHMENT0,
1118         GL_COLOR_ATTACHMENT1,
1119         GL_COLOR_ATTACHMENT2,
1120         GL_COLOR_ATTACHMENT3,
1121     };
1122 
1123     glDrawBuffers(4, bufs);
1124     drawQuad(program, positionAttrib(), 0.5);
1125 
1126     verifyAttachmentLayer(0, texture, 0, 0);
1127     verifyAttachmentLayer(1, texture, 0, 1);
1128     verifyAttachmentLayer(2, texture, 0, 2);
1129     verifyAttachmentLayer(3, texture, 0, 3);
1130 
1131     EXPECT_GL_NO_ERROR();
1132 
1133     glDeleteProgram(program);
1134 }
1135 
1136 // Test that binding multiple layers of a 2D array texture works correctly
1137 TEST_P(DrawBuffersTestES3, 2DArrayTextures)
1138 {
1139     ANGLE_SKIP_TEST_IF(!setupTest());
1140 
1141     GLTexture texture;
1142     glBindTexture(GL_TEXTURE_2D_ARRAY, texture);
1143     glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, getWindowWidth(), getWindowHeight(),
1144                  getWindowWidth(), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
1145 
1146     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, 0);
1147     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture, 0, 1);
1148     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, texture, 0, 2);
1149     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, texture, 0, 3);
1150 
1151     bool flags[8] = {true, true, true, true, false};
1152 
1153     GLuint program;
1154     setupMRTProgram(flags, &program);
1155 
1156     const GLenum bufs[] = {
1157         GL_COLOR_ATTACHMENT0,
1158         GL_COLOR_ATTACHMENT1,
1159         GL_COLOR_ATTACHMENT2,
1160         GL_COLOR_ATTACHMENT3,
1161     };
1162 
1163     glDrawBuffers(4, bufs);
1164     drawQuad(program, positionAttrib(), 0.5);
1165 
1166     verifyAttachmentLayer(0, texture, 0, 0);
1167     verifyAttachmentLayer(1, texture, 0, 1);
1168     verifyAttachmentLayer(2, texture, 0, 2);
1169     verifyAttachmentLayer(3, texture, 0, 3);
1170 
1171     EXPECT_GL_NO_ERROR();
1172 
1173     glDeleteProgram(program);
1174 }
1175 
1176 // Test that binding multiple faces of a CubeMap texture works correctly
TEST_P(DrawBuffersTestES3,CubeMapTextures)1177 TEST_P(DrawBuffersTestES3, CubeMapTextures)
1178 {
1179     ANGLE_SKIP_TEST_IF(!setupTest());
1180 
1181     GLTexture texture;
1182     glBindTexture(GL_TEXTURE_CUBE_MAP, texture);
1183     glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, GL_RGBA8, getWindowWidth(), getWindowHeight());
1184     EXPECT_GL_NO_ERROR();
1185 
1186     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, 3);
1187     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture, 0, 2);
1188     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, texture, 0, 1);
1189     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, texture, 0, 0);
1190     EXPECT_GL_NO_ERROR();
1191 
1192     bool flags[8] = {true, true, true, true, false};
1193 
1194     GLuint program;
1195     setupMRTProgram(flags, &program);
1196 
1197     const GLenum bufs[] = {
1198         GL_COLOR_ATTACHMENT0,
1199         GL_COLOR_ATTACHMENT1,
1200         GL_COLOR_ATTACHMENT2,
1201         GL_COLOR_ATTACHMENT3,
1202     };
1203 
1204     glDrawBuffers(4, bufs);
1205     drawQuad(program, positionAttrib(), 0.5);
1206 
1207     verifyAttachmentLayer(0, texture, 0, 3);
1208     verifyAttachmentLayer(1, texture, 0, 2);
1209     verifyAttachmentLayer(2, texture, 0, 1);
1210     verifyAttachmentLayer(3, texture, 0, 0);
1211 
1212     EXPECT_GL_NO_ERROR();
1213 
1214     glDeleteProgram(program);
1215 }
1216 
1217 // Test that binding multiple layers of a CubeMap array texture works correctly
TEST_P(DrawBuffersTestES3,CubeMapArrayTextures)1218 TEST_P(DrawBuffersTestES3, CubeMapArrayTextures)
1219 {
1220     ANGLE_SKIP_TEST_IF(!setupTest());
1221     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_cube_map_array"));
1222 
1223     GLTexture texture;
1224     glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, texture);
1225     glTexStorage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 1, GL_RGBA8, getWindowWidth(), getWindowHeight(),
1226                    static_cast<GLint>(kCubeFaces.size()));
1227     EXPECT_GL_NO_ERROR();
1228 
1229     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, 3);
1230     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture, 0, 2);
1231     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, texture, 0, 1);
1232     glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, texture, 0, 0);
1233     EXPECT_GL_NO_ERROR();
1234 
1235     bool flags[8] = {true, true, true, true, false};
1236 
1237     GLuint program;
1238     setupMRTProgram(flags, &program);
1239 
1240     const GLenum bufs[] = {
1241         GL_COLOR_ATTACHMENT0,
1242         GL_COLOR_ATTACHMENT1,
1243         GL_COLOR_ATTACHMENT2,
1244         GL_COLOR_ATTACHMENT3,
1245     };
1246 
1247     glDrawBuffers(4, bufs);
1248     drawQuad(program, positionAttrib(), 0.5);
1249 
1250     verifyAttachmentLayer(0, texture, 0, 3);
1251     verifyAttachmentLayer(1, texture, 0, 2);
1252     verifyAttachmentLayer(2, texture, 0, 1);
1253     verifyAttachmentLayer(3, texture, 0, 0);
1254 
1255     EXPECT_GL_NO_ERROR();
1256 
1257     glDeleteProgram(program);
1258 }
1259 
1260 // Test that blend works when draw buffers and framebuffers change.
TEST_P(DrawBuffersTestES3,BlendWithDrawBufferAndFramebufferChanges)1261 TEST_P(DrawBuffersTestES3, BlendWithDrawBufferAndFramebufferChanges)
1262 {
1263     ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_draw_buffers_indexed"));
1264 
1265     // http://anglebug.com/42263715
1266     ANGLE_SKIP_TEST_IF(IsMac() && IsIntel() && IsDesktopOpenGL());
1267 
1268     // Create two framebuffers, one with 3 attachments (fbo3), one with 4 (fbo4).  The test issues
1269     // draw calls on fbo3 with different attachments enabled, then switches to fbo4 (without
1270     // dirtying blend state) and draws to other attachments.  It ensures that blend state is
1271     // appropriately set on framebuffer change.
1272 
1273     GLenum bufs[4] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2,
1274                       GL_COLOR_ATTACHMENT3};
1275 
1276     GLFramebuffer fbo[2];
1277     GLTexture tex[7];
1278     constexpr GLfloat kClearValue[] = {1, 1, 1, 1};
1279 
1280     glBindFramebuffer(GL_FRAMEBUFFER, fbo[0]);
1281 
1282     for (uint32_t texIndex = 0; texIndex < 7; ++texIndex)
1283     {
1284         size_t colorAttachmentIndex = texIndex >= 3 ? texIndex - 3 : texIndex;
1285         if (texIndex == 3)
1286         {
1287             glBindFramebuffer(GL_FRAMEBUFFER, fbo[1]);
1288         }
1289 
1290         glBindTexture(GL_TEXTURE_2D, tex[texIndex]);
1291         glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
1292         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + colorAttachmentIndex,
1293                                GL_TEXTURE_2D, tex[texIndex], 0);
1294         EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
1295 
1296         glDrawBuffers(4, bufs);
1297         glClearBufferfv(GL_COLOR, colorAttachmentIndex, kClearValue);
1298     }
1299     ASSERT_GL_NO_ERROR();
1300 
1301     glEnablei(GL_BLEND, 0);
1302     glEnablei(GL_BLEND, 1);
1303     glEnablei(GL_BLEND, 2);
1304     glEnablei(GL_BLEND, 3);
1305 
1306     glBlendEquationi(0, GL_FUNC_REVERSE_SUBTRACT);
1307     glBlendEquationi(1, GL_MIN);
1308     glBlendEquationi(2, GL_FUNC_REVERSE_SUBTRACT);
1309     glBlendEquationi(3, GL_FUNC_REVERSE_SUBTRACT);
1310 
1311     glBlendFunci(0, GL_ONE, GL_ONE);
1312     glBlendFunci(1, GL_DST_ALPHA, GL_DST_ALPHA);
1313     glBlendFunci(2, GL_SRC_ALPHA, GL_SRC_ALPHA);
1314     glBlendFunci(3, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
1315 
1316     bufs[0] = GL_NONE;
1317     bufs[2] = GL_NONE;
1318     glDrawBuffers(4, bufs);
1319 
1320     glBindFramebuffer(GL_FRAMEBUFFER, fbo[0]);
1321 
1322     bufs[2] = GL_COLOR_ATTACHMENT2;
1323     glDrawBuffers(3, bufs);
1324 
1325     constexpr char kFS[] = R"(#version 300 es
1326 precision highp float;
1327 
1328 uniform vec4 value0;
1329 uniform vec4 value1;
1330 uniform vec4 value2;
1331 uniform vec4 value3;
1332 
1333 layout(location = 0) out vec4 color0;
1334 layout(location = 1) out vec4 color1;
1335 layout(location = 2) out vec4 color2;
1336 layout(location = 3) out vec4 color3;
1337 
1338 void main()
1339 {
1340     color0 = value0;
1341     color1 = value1;
1342     color2 = value2;
1343     color3 = value3;
1344 }
1345 )";
1346 
1347     ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
1348     glUseProgram(program);
1349 
1350     GLint uniforms[4];
1351     for (uint32_t attachmentIndex = 0; attachmentIndex < 4; ++attachmentIndex)
1352     {
1353         char uniformName[20];
1354         snprintf(uniformName, sizeof uniformName, "value%u", attachmentIndex);
1355         uniforms[attachmentIndex] = glGetUniformLocation(program, uniformName);
1356         ASSERT_NE(uniforms[attachmentIndex], -1);
1357     }
1358 
1359     // Currently, fbo3 is bound.  The attachment states are:
1360     //
1361     //     0: DISABLED Color: (1, 1, 1, 1), Blend: reverse subtract, ONE/ONE
1362     //     1:          Color: (1, 1, 1, 1), Blend: min, DST_ALPHA/DST_ALPHA
1363     //     2:          Color: (1, 1, 1, 1), Blend: reverse subtract, SRC_ALPHA/SRC_ALPHA
1364     //
1365     // Draw:
1366     //
1367     //     0: Color: don't care
1368     //     1: Color: (0.75, 0.5, 0.25, 0.5)  ->  Result after blend is: (0.75, 0.5, 0.25, 0.5)
1369     //     2: Color: (0.25, 0.5, 0.75, 0.5)  ->  Result after blend is: (0.375, 0.25, 0.125, 0.25)
1370 
1371     // Draws green into attachment 1
1372     glUniform4f(uniforms[1], 0.75, 0.5, 0.25, 0.5);
1373     glUniform4f(uniforms[2], 0.25, 0.5, 0.75, 0.5);
1374     drawQuad(program, positionAttrib(), 0.5);
1375     ASSERT_GL_NO_ERROR();
1376 
1377     bufs[0] = GL_COLOR_ATTACHMENT0;
1378     bufs[1] = GL_NONE;
1379     glDrawBuffers(3, bufs);
1380 
1381     // Currently, fbo3 is bound.  The attachment states are:
1382     //
1383     //     0:          Color: (1, 1, 1, 1), Blend: reverse subtract, ONE/ONE
1384     //     1: DISABLED Color: (0.75, 0.5, 0.25, 0.5), Blend: min, DST_ALPHA/DST_ALPHA
1385     //     2:          Color: (0.375, 0.25, 0.125, 0.25), Blend: reverse subtract,
1386     //     SRC_ALPHA/SRC_ALPHA
1387     //
1388     // Draw:
1389     //
1390     //     0: Color: (0.5, 0.25, 0.75, 0.25) ->  Result after blend is: (0.5, 0.75, 0.25, 0.75)
1391     //     1: Color: don't care
1392     //     2: Color: (0.125, 0, 0, 1)  ->  Result after blend is: (0.25, 0.25, 0.125, 0)
1393 
1394     // Clear with red
1395     glUniform4f(uniforms[0], 0.5, 0.25, 0.75, 0.25);
1396     glUniform4f(uniforms[2], 0.125, 0, 0, 1);
1397     drawQuad(program, positionAttrib(), 0.5);
1398     ASSERT_GL_NO_ERROR();
1399 
1400     glBindFramebuffer(GL_FRAMEBUFFER, fbo[1]);
1401 
1402     // Currently, fbo4 is bound.  The attachment states are:
1403     //
1404     //     0: DISABLED Color: (1, 1, 1, 1), Blend: reverse subtract, ONE/ONE
1405     //     1:          Color: (1, 1, 1, 1), Blend: min, DST_ALPHA/DST_ALPHA
1406     //     2: DISABLED Color: (1, 1, 1, 1), Blend: reverse subtract, SRC_ALPHA/SRC_ALPHA
1407     //     3:          Color: (1, 1, 1, 1), Blend: reverse subtract, ONE_MINUS_SRC_ALPHA/SRC_ALPHA
1408     //
1409     // Draw:
1410     //
1411     //     0: Color: don't care
1412     //     1: Color: (0.125, 0.5, 0.625, 0.25)  ->  Result after blend is: (0.125, 0.5, 0.625, 0.25)
1413     //     2: Color: don't care
1414     //     3: Color: (0.75, 0.25, 0.5, 0.75)  ->  Result after blend is:
1415     //                                                               (0.5625, 0.6875, 0.625, 0.5625)
1416 
1417     glUniform4f(uniforms[1], 0.125, 0.5, 0.625, 0.25);
1418     glUniform4f(uniforms[3], 0.75, 0.25, 0.5, 0.75);
1419     drawQuad(program, positionAttrib(), 0.5);
1420     ASSERT_GL_NO_ERROR();
1421 
1422     // Verify results
1423     glBindFramebuffer(GL_FRAMEBUFFER, fbo[0]);
1424     glReadBuffer(GL_COLOR_ATTACHMENT0);
1425     EXPECT_PIXEL_NEAR(0, 0, 127, 191, 63, 191, 1);
1426     glReadBuffer(GL_COLOR_ATTACHMENT1);
1427     EXPECT_PIXEL_NEAR(0, 0, 191, 127, 63, 127, 1);
1428     glReadBuffer(GL_COLOR_ATTACHMENT2);
1429     EXPECT_PIXEL_NEAR(0, 0, 63, 63, 31, 0, 1);
1430 
1431     glBindFramebuffer(GL_FRAMEBUFFER, fbo[1]);
1432     glReadBuffer(GL_COLOR_ATTACHMENT0);
1433     EXPECT_PIXEL_NEAR(0, 0, 255, 255, 255, 255, 1);
1434     glReadBuffer(GL_COLOR_ATTACHMENT1);
1435     EXPECT_PIXEL_NEAR(0, 0, 31, 127, 159, 63, 1);
1436     glReadBuffer(GL_COLOR_ATTACHMENT2);
1437     EXPECT_PIXEL_NEAR(0, 0, 255, 255, 255, 255, 1);
1438     glReadBuffer(GL_COLOR_ATTACHMENT3);
1439     EXPECT_PIXEL_NEAR(0, 0, 143, 175, 159, 143, 1);
1440 }
1441 
1442 // Test that a disabled color attachment incompatible with a fragment output
1443 // is correctly ignored and does not affect other attachments.
TEST_P(DrawBuffersTestES3,DrawWithDisabledIncompatibleAttachment)1444 TEST_P(DrawBuffersTestES3, DrawWithDisabledIncompatibleAttachment)
1445 {
1446     ANGLE_SKIP_TEST_IF(!setupTest());
1447 
1448     ASSERT_GE(mMaxDrawBuffers, 4);
1449     for (GLuint texIndex = 0; texIndex < 4; texIndex++)
1450     {
1451         glBindTexture(GL_TEXTURE_2D, mTextures[texIndex]);
1452         if (texIndex == 1)
1453         {
1454             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8UI, getWindowWidth(), getWindowHeight(), 0,
1455                          GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, nullptr);
1456         }
1457         glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + texIndex, GL_TEXTURE_2D,
1458                                mTextures[texIndex], 0);
1459     }
1460     ASSERT_GL_NO_ERROR();
1461     EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_DRAW_FRAMEBUFFER);
1462 
1463     const GLenum bufs[] = {GL_COLOR_ATTACHMENT0, GL_NONE, GL_COLOR_ATTACHMENT2,
1464                            GL_COLOR_ATTACHMENT3};
1465     setDrawBuffers(4, bufs);
1466 
1467     bool flags[8] = {true, true, true, true};
1468     GLuint program;
1469     setupMRTProgram(flags, &program);
1470 
1471     drawQuad(program, positionAttrib(), 0.5);
1472     EXPECT_GL_NO_ERROR();
1473 
1474     verifyAttachment2D(0, mTextures[0], GL_TEXTURE_2D, 0);
1475     verifyAttachment2D(2, mTextures[2], GL_TEXTURE_2D, 0);
1476     verifyAttachment2D(3, mTextures[3], GL_TEXTURE_2D, 0);
1477 
1478     glDeleteProgram(program);
1479 }
1480 
1481 // Vulkan backend is setting per buffer color mask to false for draw buffers that set to GL_NONE.
1482 // These set of tests are to test draw buffer change followed by draw/clear/blit and followed by
1483 // draw buffer change are behaving correctly.
1484 class ColorMaskForDrawBuffersTest : public DrawBuffersTest
1485 {
1486   protected:
setupColorMaskForDrawBuffersTest()1487     void setupColorMaskForDrawBuffersTest()
1488     {
1489         glBindTexture(GL_TEXTURE_2D, mTextures[0]);
1490         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0],
1491                                0);
1492         glBindTexture(GL_TEXTURE_2D, mTextures[1]);
1493         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, mTextures[1],
1494                                0);
1495         glBindTexture(GL_TEXTURE_2D, mTextures[2]);
1496         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, mTextures[2],
1497                                0);
1498 
1499         constexpr char kFS_ESSL3[] =
1500             "#version 300 es\n"
1501             "precision highp float;\n"
1502             "uniform mediump vec4 u_color0;\n"
1503             "uniform mediump vec4 u_color1;\n"
1504             "uniform mediump vec4 u_color2;\n"
1505             "layout(location = 0) out vec4 out_color0;\n"
1506             "layout(location = 1) out vec4 out_color1;\n"
1507             "layout(location = 2) out vec4 out_color2;\n"
1508             "void main()\n"
1509             "{\n"
1510             "    out_color0 = u_color0;\n"
1511             "    out_color1 = u_color1;\n"
1512             "    out_color2 = u_color2;\n"
1513             "}\n";
1514         program = CompileProgram(essl3_shaders::vs::Simple(), kFS_ESSL3);
1515         glUseProgram(program);
1516 
1517         positionLocation = glGetAttribLocation(program, positionAttrib());
1518         ASSERT_NE(-1, positionLocation);
1519         color0UniformLocation = glGetUniformLocation(program, "u_color0");
1520         ASSERT_NE(color0UniformLocation, -1);
1521         color1UniformLocation = glGetUniformLocation(program, "u_color1");
1522         ASSERT_NE(color1UniformLocation, -1);
1523         color2UniformLocation = glGetUniformLocation(program, "u_color2");
1524         ASSERT_NE(color2UniformLocation, -1);
1525 
1526         glUniform4fv(color0UniformLocation, 1, GLColor::red.toNormalizedVector().data());
1527         glUniform4fv(color1UniformLocation, 1, GLColor::green.toNormalizedVector().data());
1528         glUniform4fv(color2UniformLocation, 1, GLColor::yellow.toNormalizedVector().data());
1529 
1530         // Draw into the buffers so that buffer0 is red, buffer1 is green and buffer2 is yellow
1531         resetDrawBuffers();
1532         drawQuad(program, positionAttrib(), 0.5);
1533         EXPECT_GL_NO_ERROR();
1534 
1535         for (int i = 0; i < 4; i++)
1536         {
1537             drawBuffers[i] = GL_NONE;
1538         }
1539     }
1540 
resetDrawBuffers()1541     void resetDrawBuffers()
1542     {
1543         drawBuffers[0] = GL_COLOR_ATTACHMENT0;
1544         drawBuffers[1] = GL_COLOR_ATTACHMENT1;
1545         drawBuffers[2] = GL_COLOR_ATTACHMENT2;
1546         drawBuffers[3] = GL_NONE;
1547         setDrawBuffers(4, drawBuffers);
1548     }
1549 
1550     GLenum drawBuffers[4];
1551     GLuint program;
1552     GLint positionLocation;
1553     GLint color0UniformLocation;
1554     GLint color1UniformLocation;
1555     GLint color2UniformLocation;
1556 };
1557 
1558 // Test draw buffer state change followed draw call
TEST_P(ColorMaskForDrawBuffersTest,DrawQuad)1559 TEST_P(ColorMaskForDrawBuffersTest, DrawQuad)
1560 {
1561     ANGLE_SKIP_TEST_IF(!setupTest());
1562     setupColorMaskForDrawBuffersTest();
1563 
1564     // Draw blue into attachment0. Buffer0 should be blue and buffer1 should remain green
1565     drawBuffers[0] = GL_COLOR_ATTACHMENT0;
1566     setDrawBuffers(4, drawBuffers);
1567     glUniform4fv(color0UniformLocation, 1, GLColor::blue.toNormalizedVector().data());
1568     glUniform4fv(color1UniformLocation, 1, GLColor::cyan.toNormalizedVector().data());
1569     glViewport(0, 0, getWindowWidth() / 2, getWindowHeight() / 2);
1570     drawQuad(program, positionAttrib(), 0.5);
1571 
1572     resetDrawBuffers();
1573     glUniform4fv(color0UniformLocation, 1, GLColor::magenta.toNormalizedVector().data());
1574     glUniform4fv(color1UniformLocation, 1, GLColor::white.toNormalizedVector().data());
1575     glViewport(getWindowWidth() / 2, 0, getWindowWidth() / 2, getWindowHeight() / 2);
1576     drawQuad(program, positionAttrib(), 0.5);
1577     EXPECT_GL_NO_ERROR();
1578 
1579     glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0],
1580                            0);
1581     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
1582     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() / 4, GLColor::magenta);
1583     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() * 3 / 4, GLColor::red);
1584     glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[1],
1585                            0);
1586     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::green);
1587     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() / 4, GLColor::white);
1588     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() * 3 / 4, GLColor::green);
1589     EXPECT_GL_NO_ERROR();
1590 }
1591 
1592 // Test draw buffer state change followed clear
TEST_P(ColorMaskForDrawBuffersTest,Clear)1593 TEST_P(ColorMaskForDrawBuffersTest, Clear)
1594 {
1595     ANGLE_SKIP_TEST_IF(!setupTest());
1596     setupColorMaskForDrawBuffersTest();
1597 
1598     // Clear attachment1. Buffer0 should retain red and buffer1 should be blue
1599     drawBuffers[1] = GL_COLOR_ATTACHMENT1;
1600     setDrawBuffers(4, drawBuffers);
1601     angle::Vector4 clearColor = GLColor::blue.toNormalizedVector();
1602     glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
1603     glClear(GL_COLOR_BUFFER_BIT);
1604     verifyAttachment2DColor(0, mTextures[0], GL_TEXTURE_2D, 0, GLColor::red);
1605     verifyAttachment2DColor(1, mTextures[1], GL_TEXTURE_2D, 0, GLColor::blue);
1606     EXPECT_GL_NO_ERROR();
1607 }
1608 
1609 // Test draw buffer state change followed scissored clear
TEST_P(ColorMaskForDrawBuffersTest,ScissoredClear)1610 TEST_P(ColorMaskForDrawBuffersTest, ScissoredClear)
1611 {
1612     ANGLE_SKIP_TEST_IF(!setupTest());
1613     setupColorMaskForDrawBuffersTest();
1614 
1615     // Clear attachment1. Buffer0 should retain red and buffer1 should be blue
1616     drawBuffers[1] = GL_COLOR_ATTACHMENT1;
1617     setDrawBuffers(4, drawBuffers);
1618     angle::Vector4 clearColor = GLColor::blue.toNormalizedVector();
1619     glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
1620     glScissor(0, 0, getWindowWidth() / 2, getWindowHeight() / 2);
1621     glEnable(GL_SCISSOR_TEST);
1622     glClear(GL_COLOR_BUFFER_BIT);
1623 
1624     resetDrawBuffers();
1625     clearColor = GLColor::magenta.toNormalizedVector();
1626     glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
1627     glScissor(getWindowWidth() / 2, 0, getWindowWidth() / 2, getWindowHeight() / 2);
1628     glClear(GL_COLOR_BUFFER_BIT);
1629     EXPECT_GL_NO_ERROR();
1630 
1631     glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0],
1632                            0);
1633     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::red);
1634     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() / 4, GLColor::magenta);
1635     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() * 3 / 4, GLColor::red);
1636     glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[1],
1637                            0);
1638     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);
1639     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() / 4, GLColor::magenta);
1640     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() * 3 / 4, GLColor::green);
1641     EXPECT_GL_NO_ERROR();
1642 }
1643 
1644 // Test draw buffer state change followed FBO blit
TEST_P(ColorMaskForDrawBuffersTest,Blit)1645 TEST_P(ColorMaskForDrawBuffersTest, Blit)
1646 {
1647     ANGLE_SKIP_TEST_IF(!setupTest());
1648     setupColorMaskForDrawBuffersTest();
1649 
1650     glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[2],
1651                            0);
1652 
1653     // BLIT mTexture[2] to attachment0. Buffer0 should remain red and buffer1 should be yellow
1654     drawBuffers[0] = GL_COLOR_ATTACHMENT0;
1655     setDrawBuffers(4, drawBuffers);
1656     glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(),
1657                       getWindowHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
1658     verifyAttachment2DColor(0, mTextures[0], GL_TEXTURE_2D, 0, GLColor::yellow);
1659     verifyAttachment2DColor(1, mTextures[1], GL_TEXTURE_2D, 0, GLColor::green);
1660     EXPECT_GL_NO_ERROR();
1661 }
1662 
1663 // Test that enabling/disabling FBO draw buffers affects color mask
TEST_P(ColorMaskForDrawBuffersTest,StateChangeAffectsColorMask)1664 TEST_P(ColorMaskForDrawBuffersTest, StateChangeAffectsColorMask)
1665 {
1666     ANGLE_SKIP_TEST_IF(!setupTest());
1667     setupColorMaskForDrawBuffersTest();
1668 
1669     // Setup draw
1670     glUseProgram(program);
1671     std::array<Vector3, 6> quadVertices = GetQuadVertices();
1672     glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, quadVertices.data());
1673     glEnableVertexAttribArray(positionLocation);
1674 
1675     // Draw with some attachments disabled.  Attachments are initially, red, green and yellow.
1676     drawBuffers[0] = GL_COLOR_ATTACHMENT0;
1677     drawBuffers[1] = GL_NONE;
1678     drawBuffers[2] = GL_NONE;
1679     setDrawBuffers(4, drawBuffers);
1680     glUniform4fv(color0UniformLocation, 1, GLColor::blue.toNormalizedVector().data());
1681     glUniform4fv(color1UniformLocation, 1, GLColor::cyan.toNormalizedVector().data());
1682     // Attachment 0 is now blue
1683     glDrawArrays(GL_TRIANGLES, 0, 6);
1684     EXPECT_GL_NO_ERROR();
1685 
1686     // Draw with the second attachment enabled
1687     drawBuffers[0] = GL_COLOR_ATTACHMENT0;
1688     drawBuffers[1] = GL_COLOR_ATTACHMENT1;
1689     setDrawBuffers(4, drawBuffers);
1690     glUniform4fv(color0UniformLocation, 1, GLColor::magenta.toNormalizedVector().data());
1691     glUniform4fv(color1UniformLocation, 1, GLColor::white.toNormalizedVector().data());
1692     // Attachment 0 is now magenta, and attachment 1 is white.  Attachment 2 is still yellow.
1693     glDrawArrays(GL_TRIANGLES, 0, 6);
1694     EXPECT_GL_NO_ERROR();
1695 
1696     // Check second attachment was updated by the second draw
1697     glBindFramebuffer(GL_READ_FRAMEBUFFER, mFBO);
1698     glReadBuffer(GL_COLOR_ATTACHMENT0);
1699     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
1700     glReadBuffer(GL_COLOR_ATTACHMENT1);
1701     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
1702     glReadBuffer(GL_COLOR_ATTACHMENT2);
1703     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
1704     EXPECT_GL_NO_ERROR();
1705 }
1706 
1707 // Test that enabling/disabling FBO draw buffers affects blend state appropriately as well as the
1708 // color mask.
TEST_P(ColorMaskForDrawBuffersTest,StateChangeAffectsBlendState)1709 TEST_P(ColorMaskForDrawBuffersTest, StateChangeAffectsBlendState)
1710 {
1711     ANGLE_SKIP_TEST_IF(!setupTest());
1712     setupColorMaskForDrawBuffersTest();
1713 
1714     glEnable(GL_BLEND);
1715     glBlendFunc(GL_ONE, GL_ONE);
1716 
1717     // Setup draw
1718     glUseProgram(program);
1719     std::array<Vector3, 6> quadVertices = GetQuadVertices();
1720     glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, quadVertices.data());
1721     glEnableVertexAttribArray(positionLocation);
1722 
1723     // Draw with some attachments disabled.  Attachments are initially, red, green and yellow.
1724     drawBuffers[0] = GL_COLOR_ATTACHMENT0;
1725     drawBuffers[1] = GL_NONE;
1726     drawBuffers[2] = GL_NONE;
1727     setDrawBuffers(4, drawBuffers);
1728     glUniform4fv(color0UniformLocation, 1, GLColor::blue.toNormalizedVector().data());
1729     glUniform4fv(color1UniformLocation, 1, GLColor::cyan.toNormalizedVector().data());
1730     // Attachment 0 is now magenta.
1731     glDrawArrays(GL_TRIANGLES, 0, 6);
1732     EXPECT_GL_NO_ERROR();
1733 
1734     // Draw with the second attachment enabled
1735     drawBuffers[0] = GL_COLOR_ATTACHMENT0;
1736     drawBuffers[1] = GL_COLOR_ATTACHMENT1;
1737     setDrawBuffers(4, drawBuffers);
1738     glUniform4fv(color0UniformLocation, 1, GLColor::green.toNormalizedVector().data());
1739     glUniform4fv(color1UniformLocation, 1, GLColor::blue.toNormalizedVector().data());
1740     // Attachment 0 is now white, attachment 1 is cyan and attachment 2 is still yellow.
1741     glDrawArrays(GL_TRIANGLES, 0, 6);
1742     EXPECT_GL_NO_ERROR();
1743 
1744     // Check second attachment was updated by the second draw
1745     glBindFramebuffer(GL_READ_FRAMEBUFFER, mFBO);
1746     glReadBuffer(GL_COLOR_ATTACHMENT0);
1747     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
1748     glReadBuffer(GL_COLOR_ATTACHMENT1);
1749     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);
1750     glReadBuffer(GL_COLOR_ATTACHMENT2);
1751     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
1752     EXPECT_GL_NO_ERROR();
1753 }
1754 
1755 ANGLE_INSTANTIATE_TEST(DrawBuffersTest,
1756                        ANGLE_ALL_TEST_PLATFORMS_ES2,
1757                        ANGLE_ALL_TEST_PLATFORMS_ES3,
1758                        ES2_METAL().enable(Feature::LimitMaxDrawBuffersForTesting),
1759                        ES2_VULKAN()
1760                            .disable(Feature::SupportsTransformFeedbackExtension)
1761                            .disable(Feature::EmulateTransformFeedback));
1762 
1763 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DrawBuffersWebGL2Test);
1764 ANGLE_INSTANTIATE_TEST_ES3(DrawBuffersWebGL2Test);
1765 
1766 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DrawBuffersTestES3);
1767 ANGLE_INSTANTIATE_TEST_ES3(DrawBuffersTestES3);
1768 
1769 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ColorMaskForDrawBuffersTest);
1770 ANGLE_INSTANTIATE_TEST_ES3(ColorMaskForDrawBuffersTest);
1771