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