Path: blob/main_old/src/tests/gl_tests/DrawBuffersTest.cpp
1693 views
//1// Copyright 2015 The ANGLE Project Authors. All rights reserved.2// Use of this source code is governed by a BSD-style license that can be3// found in the LICENSE file.4//56#include "test_utils/ANGLETest.h"7#include "test_utils/gl_raii.h"89using namespace angle;1011class DrawBuffersTest : public ANGLETest12{13protected:14DrawBuffersTest()15{16setWindowWidth(128);17setWindowHeight(128);18setConfigRedBits(8);19setConfigGreenBits(8);20setConfigBlueBits(8);21setConfigAlphaBits(8);22setConfigDepthBits(24);23}2425void testTearDown() override26{27glDeleteFramebuffers(1, &mFBO);28glDeleteFramebuffers(1, &mReadFramebuffer);29glDeleteTextures(4, mTextures);30}3132// We must call a different DrawBuffers method depending on extension support. Use this33// method instead of calling on directly.34void setDrawBuffers(GLsizei n, const GLenum *drawBufs)35{36if (IsGLExtensionEnabled("GL_EXT_draw_buffers"))37{38glDrawBuffersEXT(n, drawBufs);39}40else41{42ASSERT_GE(getClientMajorVersion(), 3);43glDrawBuffers(n, drawBufs);44}45}4647// Use this method to filter if we can support these tests.48bool setupTest()49{50if (getClientMajorVersion() < 3 && (!EnsureGLExtensionEnabled("GL_EXT_draw_buffers") ||51!EnsureGLExtensionEnabled("GL_ANGLE_framebuffer_blit")))52{53return false;54}5556// This test seems to fail on an nVidia machine when the window is hidden57setWindowVisible(getOSWindow(), true);5859glGenFramebuffers(1, &mFBO);60glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFBO);6162glGenTextures(4, mTextures);6364for (size_t texIndex = 0; texIndex < ArraySize(mTextures); texIndex++)65{66glBindTexture(GL_TEXTURE_2D, mTextures[texIndex]);67glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA,68GL_UNSIGNED_BYTE, nullptr);69}7071glGetIntegerv(GL_MAX_DRAW_BUFFERS, &mMaxDrawBuffers);7273glGenFramebuffers(1, &mReadFramebuffer);74glBindFramebuffer(GL_READ_FRAMEBUFFER, mReadFramebuffer);7576return true;77}7879void setupMRTProgramESSL3(bool bufferEnabled[8], GLuint *programOut)80{81std::stringstream strstr;8283strstr << "#version 300 es\n"84"precision highp float;\n";8586for (unsigned int index = 0; index < 8; index++)87{88if (bufferEnabled[index])89{90strstr << "layout(location = " << index91<< ") "92"out vec4 value"93<< index << ";\n";94}95}9697strstr << "void main()\n"98"{\n";99100for (unsigned int index = 0; index < 8; index++)101{102if (bufferEnabled[index])103{104unsigned int r = (index + 1) & 1;105unsigned int g = (index + 1) & 2;106unsigned int b = (index + 1) & 4;107108strstr << " value" << index << " = vec4(" << r << ".0, " << g << ".0, " << b109<< ".0, 1.0);\n";110}111}112113strstr << "}\n";114115*programOut = CompileProgram(essl3_shaders::vs::Simple(), strstr.str().c_str());116if (*programOut == 0)117{118FAIL() << "shader compilation failed.";119}120}121122void setupMRTProgramESSL1(bool bufferEnabled[8], GLuint *programOut)123{124std::stringstream strstr;125126strstr << "#extension GL_EXT_draw_buffers : enable\n"127"precision highp float;\n"128"void main()\n"129"{\n";130131for (unsigned int index = 0; index < 8; index++)132{133if (bufferEnabled[index])134{135unsigned int r = (index + 1) & 1;136unsigned int g = (index + 1) & 2;137unsigned int b = (index + 1) & 4;138139strstr << " gl_FragData[" << index << "] = vec4(" << r << ".0, " << g << ".0, "140<< b << ".0, 1.0);\n";141}142}143144strstr << "}\n";145146*programOut = CompileProgram(essl1_shaders::vs::Simple(), strstr.str().c_str());147if (*programOut == 0)148{149FAIL() << "shader compilation failed.";150}151}152153void setupMRTProgram(bool bufferEnabled[8], GLuint *programOut)154{155if (getClientMajorVersion() == 3)156{157setupMRTProgramESSL3(bufferEnabled, programOut);158}159else160{161ASSERT_EQ(getClientMajorVersion(), 2);162setupMRTProgramESSL1(bufferEnabled, programOut);163}164}165166const char *positionAttrib()167{168if (getClientMajorVersion() == 3)169{170return essl3_shaders::PositionAttrib();171}172else173{174return essl1_shaders::PositionAttrib();175}176}177178static GLColor getColorForIndex(unsigned int index)179{180GLubyte r = (((index + 1) & 1) > 0) ? 255 : 0;181GLubyte g = (((index + 1) & 2) > 0) ? 255 : 0;182GLubyte b = (((index + 1) & 4) > 0) ? 255 : 0;183return GLColor(r, g, b, 255u);184}185186void verifyAttachment2DColor(unsigned int index,187GLuint textureName,188GLenum target,189GLint level,190GLColor color)191{192glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, textureName,193level);194EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, color)195<< "index " << index;196}197198void verifyAttachment2DUnwritten(unsigned int index, GLuint texture, GLenum target, GLint level)199{200verifyAttachment2DColor(index, texture, target, level, GLColor::transparentBlack);201}202203void verifyAttachment2D(unsigned int index, GLuint texture, GLenum target, GLint level)204{205verifyAttachment2DColor(index, texture, target, level, getColorForIndex(index));206}207208void verifyAttachment3DOES(unsigned int index, GLuint texture, GLint level, GLint layer)209{210ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_3D"));211212glFramebufferTexture3DOES(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, texture,213level, layer);214EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, getColorForIndex(index));215}216217void verifyAttachmentLayer(unsigned int index, GLuint texture, GLint level, GLint layer)218{219glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, level, layer);220EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, getColorForIndex(index));221}222223GLuint mFBO = 0;224GLuint mReadFramebuffer = 0;225GLuint mTextures[4] = {};226GLint mMaxDrawBuffers = 0;227};228229class DrawBuffersWebGL2Test : public DrawBuffersTest230{231public:232DrawBuffersWebGL2Test()233{234setWebGLCompatibilityEnabled(true);235setRobustResourceInit(true);236}237};238239// Verify that GL_MAX_DRAW_BUFFERS returns the expected values for D3D11240TEST_P(DrawBuffersTest, VerifyD3DLimits)241{242EGLPlatformParameters platform = GetParam().eglParameters;243244ANGLE_SKIP_TEST_IF(platform.renderer != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE);245246glGetIntegerv(GL_MAX_DRAW_BUFFERS, &mMaxDrawBuffers);247248if (platform.majorVersion == 9 && platform.minorVersion == 3)249{250// D3D11 Feature Level 9_3 supports 4 draw buffers251ASSERT_EQ(mMaxDrawBuffers, 4);252}253else254{255// D3D11 Feature Level 10_0+ supports 8 draw buffers256ASSERT_EQ(mMaxDrawBuffers, 8);257}258}259260TEST_P(DrawBuffersTest, Gaps)261{262ANGLE_SKIP_TEST_IF(!setupTest());263264// TODO(ynovikov): Investigate the failure (http://anglebug.com/1535)265ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsDesktopOpenGL());266267// TODO(syoussefi): Qualcomm driver crashes in the presence of VK_ATTACHMENT_UNUSED.268// http://anglebug.com/3423269ANGLE_SKIP_TEST_IF(IsVulkan() && IsAndroid());270271// Fails on Intel Ubuntu 19.04 Mesa 19.0.2 Vulkan. http://anglebug.com/3616272ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel() && IsVulkan());273274glBindTexture(GL_TEXTURE_2D, mTextures[0]);275glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, mTextures[0], 0);276277bool flags[8] = {false, true};278279GLuint program;280setupMRTProgram(flags, &program);281282const GLenum bufs[] = {GL_NONE, GL_COLOR_ATTACHMENT1};283setDrawBuffers(2, bufs);284drawQuad(program, positionAttrib(), 0.5);285286verifyAttachment2D(1, mTextures[0], GL_TEXTURE_2D, 0);287288glDeleteProgram(program);289}290291// Test that blend works with gaps292TEST_P(DrawBuffersTest, BlendWithGaps)293{294ANGLE_SKIP_TEST_IF(!setupTest());295296// Qualcomm driver crashes in the presence of VK_ATTACHMENT_UNUSED.297// http://anglebug.com/3423298ANGLE_SKIP_TEST_IF(IsVulkan() && IsAndroid());299300// Fails on Intel Ubuntu 19.04 Mesa 19.0.2 Vulkan. http://anglebug.com/3616301ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel() && IsVulkan());302303// http://anglebug.com/5154304ANGLE_SKIP_TEST_IF(IsOSX() && IsIntel() && IsDesktopOpenGL());305306glBindTexture(GL_TEXTURE_2D, mTextures[0]);307glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, mTextures[0], 0);308309ASSERT_GL_NO_ERROR();310311bool flags[8] = {false, true};312313GLuint program;314setupMRTProgram(flags, &program);315316const GLenum bufs[] = {GL_NONE, GL_COLOR_ATTACHMENT1};317setDrawBuffers(2, bufs);318319// Draws green into attachment 1320drawQuad(program, positionAttrib(), 0.5);321verifyAttachment2D(1, mTextures[0], GL_TEXTURE_2D, 0);322ASSERT_GL_NO_ERROR();323324// Clear with red325glClearColor(1.0, 0.0, 0.0, 1.0);326glClear(GL_COLOR_BUFFER_BIT);327verifyAttachment2DColor(1, mTextures[0], GL_TEXTURE_2D, 0, GLColor(255u, 0, 0, 255u));328329// Draw green into attachment 1 again but with blending, expecting yellow330glEnable(GL_BLEND);331glBlendFunc(GL_ONE, GL_ONE);332drawQuad(program, positionAttrib(), 0.5);333verifyAttachment2DColor(1, mTextures[0], GL_TEXTURE_2D, 0, GLColor(255u, 255u, 0, 255u));334ASSERT_GL_NO_ERROR();335336glDeleteProgram(program);337}338339// Test that clear works with gaps340TEST_P(DrawBuffersTest, ClearWithGaps)341{342// TODO(syoussefi): Qualcomm driver crashes in the presence of VK_ATTACHMENT_UNUSED.343// http://anglebug.com/3423344ANGLE_SKIP_TEST_IF(IsVulkan() && IsAndroid());345346ANGLE_SKIP_TEST_IF(!setupTest());347348glGetIntegerv(GL_MAX_DRAW_BUFFERS, &mMaxDrawBuffers);349ASSERT_GE(mMaxDrawBuffers, 4);350351glBindTexture(GL_TEXTURE_2D, mTextures[0]);352glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);353354glBindTexture(GL_TEXTURE_2D, mTextures[1]);355glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, mTextures[1], 0);356357const GLenum bufs[] = {GL_COLOR_ATTACHMENT0, GL_NONE, GL_NONE, GL_COLOR_ATTACHMENT3};358359bool flags[8] = {true, false, false, true};360GLuint program;361setupMRTProgram(flags, &program);362363setDrawBuffers(4, bufs);364365glClearColor(1.0f, 1.0f, 0.0f, 1.0f);366glClear(GL_COLOR_BUFFER_BIT);367368// A bogus draw to make sure clears are done with a render pass in the Vulkan backend.369glEnable(GL_BLEND);370glBlendFunc(GL_ZERO, GL_ONE);371drawQuad(program, positionAttrib(), 0.5);372EXPECT_GL_NO_ERROR();373374verifyAttachment2DColor(0, mTextures[0], GL_TEXTURE_2D, 0, GLColor::yellow);375verifyAttachment2DColor(3, mTextures[1], GL_TEXTURE_2D, 0, GLColor::yellow);376377EXPECT_GL_NO_ERROR();378}379380TEST_P(DrawBuffersTest, FirstAndLast)381{382ANGLE_SKIP_TEST_IF(!setupTest());383384// TODO(ynovikov): Investigate the failure (https://anglebug.com/1533)385ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsDesktopOpenGL());386387// TODO(syoussefi): Qualcomm driver crashes in the presence of VK_ATTACHMENT_UNUSED.388// http://anglebug.com/3423389ANGLE_SKIP_TEST_IF(IsVulkan() && IsAndroid());390391glBindTexture(GL_TEXTURE_2D, mTextures[0]);392glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);393394glBindTexture(GL_TEXTURE_2D, mTextures[1]);395glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, mTextures[1], 0);396397bool flags[8] = {true, false, false, true};398399GLuint program;400setupMRTProgram(flags, &program);401402const GLenum bufs[] = {GL_COLOR_ATTACHMENT0, GL_NONE, GL_NONE, GL_COLOR_ATTACHMENT3};403404setDrawBuffers(4, bufs);405drawQuad(program, positionAttrib(), 0.5);406407verifyAttachment2D(0, mTextures[0], GL_TEXTURE_2D, 0);408verifyAttachment2D(3, mTextures[1], GL_TEXTURE_2D, 0);409410EXPECT_GL_NO_ERROR();411412glDeleteProgram(program);413}414415TEST_P(DrawBuffersTest, FirstHalfNULL)416{417ANGLE_SKIP_TEST_IF(!setupTest());418419// TODO(ynovikov): Investigate the failure (https://anglebug.com/1533)420ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsDesktopOpenGL());421422// TODO(syoussefi): Qualcomm driver crashes in the presence of VK_ATTACHMENT_UNUSED.423// http://anglebug.com/3423424ANGLE_SKIP_TEST_IF(IsVulkan() && IsAndroid());425426// Fails on Intel Ubuntu 19.04 Mesa 19.0.2 Vulkan. http://anglebug.com/3616427ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel() && IsVulkan());428429bool flags[8] = {false};430GLenum bufs[8] = {GL_NONE};431432GLuint halfMaxDrawBuffers = static_cast<GLuint>(mMaxDrawBuffers) / 2;433434for (GLuint texIndex = 0; texIndex < halfMaxDrawBuffers; texIndex++)435{436glBindTexture(GL_TEXTURE_2D, mTextures[texIndex]);437glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + halfMaxDrawBuffers + texIndex,438GL_TEXTURE_2D, mTextures[texIndex], 0);439flags[texIndex + halfMaxDrawBuffers] = true;440bufs[texIndex + halfMaxDrawBuffers] = GL_COLOR_ATTACHMENT0 + halfMaxDrawBuffers + texIndex;441}442443GLuint program;444setupMRTProgram(flags, &program);445446setDrawBuffers(mMaxDrawBuffers, bufs);447drawQuad(program, positionAttrib(), 0.5);448449for (GLuint texIndex = 0; texIndex < halfMaxDrawBuffers; texIndex++)450{451verifyAttachment2D(texIndex + halfMaxDrawBuffers, mTextures[texIndex], GL_TEXTURE_2D, 0);452}453454EXPECT_GL_NO_ERROR();455456glDeleteProgram(program);457}458459// Test that non-zero draw buffers can be queried on the default framebuffer460TEST_P(DrawBuffersTest, DefaultFramebufferDrawBufferQuery)461{462ANGLE_SKIP_TEST_IF(!setupTest());463464glBindFramebuffer(GL_FRAMEBUFFER, 0);465466GLint drawbuffer = 0;467glGetIntegerv(GL_DRAW_BUFFER1, &drawbuffer);468EXPECT_GL_NO_ERROR();469470EXPECT_EQ(GL_NONE, drawbuffer);471}472473// Same as above but adds a state change from a program with different masks after a clear.474TEST_P(DrawBuffersWebGL2Test, TwoProgramsWithDifferentOutputsAndClear)475{476// TODO(http://anglebug.com/2872): Broken on the GL back-end.477ANGLE_SKIP_TEST_IF(IsOpenGL());478479// TODO(ynovikov): Investigate the failure (https://anglebug.com/1533)480ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsDesktopOpenGL());481482// TODO(syoussefi): Qualcomm driver crashes in the presence of VK_ATTACHMENT_UNUSED.483// http://anglebug.com/3423484ANGLE_SKIP_TEST_IF(IsVulkan() && IsAndroid());485486ANGLE_SKIP_TEST_IF(!setupTest());487488glGetIntegerv(GL_MAX_DRAW_BUFFERS, &mMaxDrawBuffers);489ASSERT_GE(mMaxDrawBuffers, 4);490491bool flags[8] = {false};492GLenum someBufs[4] = {GL_NONE};493GLenum allBufs[4] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2,494GL_COLOR_ATTACHMENT3};495496constexpr GLuint kMaxBuffers = 4;497constexpr GLuint kHalfMaxBuffers = 2;498499// Enable all draw buffers.500for (GLuint texIndex = 0; texIndex < kMaxBuffers; texIndex++)501{502glBindTexture(GL_TEXTURE_2D, mTextures[texIndex]);503glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + texIndex, GL_TEXTURE_2D,504mTextures[texIndex], 0);505someBufs[texIndex] =506texIndex >= kHalfMaxBuffers ? GL_COLOR_ATTACHMENT0 + texIndex : GL_NONE;507508// Mask out the first two buffers.509flags[texIndex] = texIndex >= kHalfMaxBuffers;510}511512GLuint program;513setupMRTProgram(flags, &program);514515// Now set up a second simple program that draws to FragColor. Should be broadcast.516ANGLE_GL_PROGRAM(simpleProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());517518// Draw with simple program.519drawQuad(simpleProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);520ASSERT_GL_NO_ERROR();521522// Clear draw buffers.523setDrawBuffers(kMaxBuffers, someBufs);524glClearColor(0.0f, 1.0f, 0.0f, 1.0f);525glClear(GL_COLOR_BUFFER_BIT);526527ASSERT_GL_NO_ERROR();528529// Verify first is drawn red, second is untouched, and last two are cleared green.530verifyAttachment2DColor(0, mTextures[0], GL_TEXTURE_2D, 0, GLColor::red);531verifyAttachment2DColor(1, mTextures[1], GL_TEXTURE_2D, 0, GLColor::transparentBlack);532verifyAttachment2DColor(2, mTextures[2], GL_TEXTURE_2D, 0, GLColor::green);533verifyAttachment2DColor(3, mTextures[3], GL_TEXTURE_2D, 0, GLColor::green);534535// Draw with MRT program.536setDrawBuffers(kMaxBuffers, someBufs);537drawQuad(program, positionAttrib(), 0.5, 1.0f, true);538ASSERT_GL_NO_ERROR();539540// Only the last two attachments should be updated.541verifyAttachment2DColor(0, mTextures[0], GL_TEXTURE_2D, 0, GLColor::red);542verifyAttachment2DColor(1, mTextures[1], GL_TEXTURE_2D, 0, GLColor::transparentBlack);543verifyAttachment2D(2, mTextures[2], GL_TEXTURE_2D, 0);544verifyAttachment2D(3, mTextures[3], GL_TEXTURE_2D, 0);545546// Active draw buffers with no fragment output is not allowed.547setDrawBuffers(kMaxBuffers, allBufs);548drawQuad(program, positionAttrib(), 0.5, 1.0f, true);549ASSERT_GL_ERROR(GL_INVALID_OPERATION);550// Exception: when RASTERIZER_DISCARD is enabled.551glEnable(GL_RASTERIZER_DISCARD);552drawQuad(program, positionAttrib(), 0.5, 1.0f, true);553ASSERT_GL_NO_ERROR();554glDisable(GL_RASTERIZER_DISCARD);555// Exception: when all 4 channels of color mask are set to false.556glColorMask(false, false, false, false);557drawQuad(program, positionAttrib(), 0.5, 1.0f, true);558ASSERT_GL_NO_ERROR();559glColorMask(false, true, false, false);560drawQuad(program, positionAttrib(), 0.5, 1.0f, true);561ASSERT_GL_ERROR(GL_INVALID_OPERATION);562glColorMask(true, true, true, true);563drawQuad(program, positionAttrib(), 0.5, 1.0f, true);564ASSERT_GL_ERROR(GL_INVALID_OPERATION);565566// Clear again. All attachments should be cleared.567glClear(GL_COLOR_BUFFER_BIT);568verifyAttachment2DColor(0, mTextures[0], GL_TEXTURE_2D, 0, GLColor::green);569verifyAttachment2DColor(1, mTextures[1], GL_TEXTURE_2D, 0, GLColor::green);570verifyAttachment2DColor(2, mTextures[2], GL_TEXTURE_2D, 0, GLColor::green);571verifyAttachment2DColor(3, mTextures[3], GL_TEXTURE_2D, 0, GLColor::green);572573glDeleteProgram(program);574}575576// Test clear with gaps in draw buffers, originally show up as577// webgl_conformance_vulkan_passthrough_tests conformance/extensions/webgl-draw-buffers.html578// failure. This is added for ease of debugging.579TEST_P(DrawBuffersWebGL2Test, Clear)580{581ANGLE_SKIP_TEST_IF(!setupTest());582583constexpr GLint kMaxBuffers = 4;584585glGetIntegerv(GL_MAX_DRAW_BUFFERS, &mMaxDrawBuffers);586ASSERT_GE(mMaxDrawBuffers, kMaxBuffers);587588GLenum drawBufs[kMaxBuffers] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,589GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3};590591// Enable all draw buffers.592for (GLuint texIndex = 0; texIndex < kMaxBuffers; texIndex++)593{594glBindTexture(GL_TEXTURE_2D, mTextures[texIndex]);595glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + texIndex, GL_TEXTURE_2D,596mTextures[texIndex], 0);597}598599// Clear with all draw buffers.600setDrawBuffers(kMaxBuffers, drawBufs);601glClearColor(1.0f, 0.0f, 0.0f, 1.0f);602glClear(GL_COLOR_BUFFER_BIT);603604// Clear with first half none draw buffers.605drawBufs[0] = GL_NONE;606drawBufs[1] = GL_NONE;607setDrawBuffers(kMaxBuffers, drawBufs);608glClearColor(0.0f, 1.0f, 0.0f, 1.0f);609glClear(GL_COLOR_BUFFER_BIT);610611ASSERT_GL_NO_ERROR();612613// Verify first is drawn red, second is untouched, and last two are cleared green.614verifyAttachment2DColor(0, mTextures[0], GL_TEXTURE_2D, 0, GLColor::red);615verifyAttachment2DColor(1, mTextures[1], GL_TEXTURE_2D, 0, GLColor::red);616verifyAttachment2DColor(2, mTextures[2], GL_TEXTURE_2D, 0, GLColor::green);617verifyAttachment2DColor(3, mTextures[3], GL_TEXTURE_2D, 0, GLColor::green);618}619620TEST_P(DrawBuffersTest, UnwrittenOutputVariablesShouldNotCrash)621{622ANGLE_SKIP_TEST_IF(!setupTest());623624// Bind two render targets but use a shader which writes only to the first one.625glBindTexture(GL_TEXTURE_2D, mTextures[0]);626glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);627628glBindTexture(GL_TEXTURE_2D, mTextures[1]);629glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, mTextures[1], 0);630631bool flags[8] = {true, false};632633GLuint program;634setupMRTProgram(flags, &program);635636const GLenum bufs[] = {637GL_COLOR_ATTACHMENT0,638GL_COLOR_ATTACHMENT1,639GL_NONE,640GL_NONE,641};642643setDrawBuffers(4, bufs);644645// This call should not crash when we dynamically generate the HLSL code.646drawQuad(program, positionAttrib(), 0.5);647648verifyAttachment2D(0, mTextures[0], GL_TEXTURE_2D, 0);649650EXPECT_GL_NO_ERROR();651652glDeleteProgram(program);653}654655TEST_P(DrawBuffersTest, BroadcastGLFragColor)656{657// Broadcast is not supported on GLES 3.0.658ANGLE_SKIP_TEST_IF(getClientMajorVersion() >= 3);659ANGLE_SKIP_TEST_IF(!setupTest());660661// Bind two render targets. gl_FragColor should be broadcast to both.662glBindTexture(GL_TEXTURE_2D, mTextures[0]);663glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0], 0);664665glBindTexture(GL_TEXTURE_2D, mTextures[1]);666glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, mTextures[1], 0);667668const GLenum bufs[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};669670constexpr char kFS[] =671"#extension GL_EXT_draw_buffers : enable\n"672"precision highp float;\n"673"uniform float u_zero;\n"674"void main()\n"675"{\n"676" gl_FragColor = vec4(1, 0, 0, 1);\n"677" if (u_zero < 1.0)\n"678" {\n"679" return;\n"680" }\n"681"}\n";682683GLuint program = CompileProgram(essl1_shaders::vs::Simple(), kFS);684if (program == 0)685{686FAIL() << "shader compilation failed.";687}688689setDrawBuffers(2, bufs);690drawQuad(program, essl1_shaders::PositionAttrib(), 0.5);691692verifyAttachment2D(0, mTextures[0], GL_TEXTURE_2D, 0);693verifyAttachment2D(0, mTextures[1], GL_TEXTURE_2D, 0);694695EXPECT_GL_NO_ERROR();696697glDeleteProgram(program);698}699700// Test that binding multiple layers of a 3D texture works correctly.701// This is the same as DrawBuffersTestES3.3DTextures but is used for GL_OES_texture_3D extension702// on GLES 2.0 instead.703TEST_P(DrawBuffersTest, 3DTexturesOES)704{705ANGLE_SKIP_TEST_IF(!setupTest());706ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_3D"));707708GLTexture texture;709glBindTexture(GL_TEXTURE_3D, texture.get());710glTexImage3DOES(GL_TEXTURE_3D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(),711getWindowWidth(), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);712713glFramebufferTexture3DOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, texture.get(), 0,7140);715glFramebufferTexture3DOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_3D, texture.get(), 0,7161);717glFramebufferTexture3DOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_3D, texture.get(), 0,7182);719glFramebufferTexture3DOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_3D, texture.get(), 0,7203);721722bool flags[8] = {true, true, true, true, false};723724GLuint program;725setupMRTProgram(flags, &program);726727const GLenum bufs[] = {728GL_COLOR_ATTACHMENT0,729GL_COLOR_ATTACHMENT1,730GL_COLOR_ATTACHMENT2,731GL_COLOR_ATTACHMENT3,732};733734setDrawBuffers(4, bufs);735drawQuad(program, positionAttrib(), 0.5);736737verifyAttachment3DOES(0, texture.get(), 0, 0);738verifyAttachment3DOES(1, texture.get(), 0, 1);739verifyAttachment3DOES(2, texture.get(), 0, 2);740verifyAttachment3DOES(3, texture.get(), 0, 3);741742EXPECT_GL_NO_ERROR();743744glDeleteProgram(program);745}746747class DrawBuffersTestES3 : public DrawBuffersTest748{};749750// Test that binding multiple layers of a 3D texture works correctly751TEST_P(DrawBuffersTestES3, 3DTextures)752{753ANGLE_SKIP_TEST_IF(!setupTest());754755GLTexture texture;756glBindTexture(GL_TEXTURE_3D, texture.get());757glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), getWindowWidth(),7580, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);759760glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.get(), 0, 0);761glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture.get(), 0, 1);762glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, texture.get(), 0, 2);763glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, texture.get(), 0, 3);764765bool flags[8] = {true, true, true, true, false};766767GLuint program;768setupMRTProgram(flags, &program);769770const GLenum bufs[] = {771GL_COLOR_ATTACHMENT0,772GL_COLOR_ATTACHMENT1,773GL_COLOR_ATTACHMENT2,774GL_COLOR_ATTACHMENT3,775};776777glDrawBuffers(4, bufs);778drawQuad(program, positionAttrib(), 0.5);779780verifyAttachmentLayer(0, texture.get(), 0, 0);781verifyAttachmentLayer(1, texture.get(), 0, 1);782verifyAttachmentLayer(2, texture.get(), 0, 2);783verifyAttachmentLayer(3, texture.get(), 0, 3);784785EXPECT_GL_NO_ERROR();786787glDeleteProgram(program);788}789790// Test that binding multiple layers of a 2D array texture works correctly791TEST_P(DrawBuffersTestES3, 2DArrayTextures)792{793ANGLE_SKIP_TEST_IF(!setupTest());794795GLTexture texture;796glBindTexture(GL_TEXTURE_2D_ARRAY, texture.get());797glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, getWindowWidth(), getWindowHeight(),798getWindowWidth(), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);799800glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture.get(), 0, 0);801glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture.get(), 0, 1);802glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, texture.get(), 0, 2);803glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, texture.get(), 0, 3);804805bool flags[8] = {true, true, true, true, false};806807GLuint program;808setupMRTProgram(flags, &program);809810const GLenum bufs[] = {811GL_COLOR_ATTACHMENT0,812GL_COLOR_ATTACHMENT1,813GL_COLOR_ATTACHMENT2,814GL_COLOR_ATTACHMENT3,815};816817glDrawBuffers(4, bufs);818drawQuad(program, positionAttrib(), 0.5);819820verifyAttachmentLayer(0, texture.get(), 0, 0);821verifyAttachmentLayer(1, texture.get(), 0, 1);822verifyAttachmentLayer(2, texture.get(), 0, 2);823verifyAttachmentLayer(3, texture.get(), 0, 3);824825EXPECT_GL_NO_ERROR();826827glDeleteProgram(program);828}829830// Vulkan backend is setting per buffer color mask to false for draw buffers that set to GL_NONE.831// These set of tests are to test draw buffer change followed by draw/clear/blit and followed by832// draw buffer change are behaving correctly.833class ColorMaskForDrawBuffersTest : public DrawBuffersTest834{835protected:836void setupColorMaskForDrawBuffersTest()837{838glBindTexture(GL_TEXTURE_2D, mTextures[0]);839glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0],8400);841glBindTexture(GL_TEXTURE_2D, mTextures[1]);842glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, mTextures[1],8430);844glBindTexture(GL_TEXTURE_2D, mTextures[2]);845glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, mTextures[2],8460);847848constexpr char kFS_ESSL3[] =849"#version 300 es\n"850"precision highp float;\n"851"uniform mediump vec4 u_color0;\n"852"uniform mediump vec4 u_color1;\n"853"uniform mediump vec4 u_color2;\n"854"layout(location = 0) out vec4 out_color0;\n"855"layout(location = 1) out vec4 out_color1;\n"856"layout(location = 2) out vec4 out_color2;\n"857"void main()\n"858"{\n"859" out_color0 = u_color0;\n"860" out_color1 = u_color1;\n"861" out_color2 = u_color2;\n"862"}\n";863program = CompileProgram(essl3_shaders::vs::Simple(), kFS_ESSL3);864glUseProgram(program);865866positionLocation = glGetAttribLocation(program, positionAttrib());867ASSERT_NE(-1, positionLocation);868color0UniformLocation = glGetUniformLocation(program, "u_color0");869ASSERT_NE(color0UniformLocation, -1);870color1UniformLocation = glGetUniformLocation(program, "u_color1");871ASSERT_NE(color1UniformLocation, -1);872color2UniformLocation = glGetUniformLocation(program, "u_color2");873ASSERT_NE(color2UniformLocation, -1);874875glUniform4fv(color0UniformLocation, 1, GLColor::red.toNormalizedVector().data());876glUniform4fv(color1UniformLocation, 1, GLColor::green.toNormalizedVector().data());877glUniform4fv(color2UniformLocation, 1, GLColor::yellow.toNormalizedVector().data());878879// First draw into both buffers so that buffer0 is red and buffer1 is green880resetDrawBuffers();881drawQuad(program, positionAttrib(), 0.5);882EXPECT_GL_NO_ERROR();883884for (int i = 0; i < 4; i++)885{886drawBuffers[i] = GL_NONE;887}888}889890void resetDrawBuffers()891{892drawBuffers[0] = GL_COLOR_ATTACHMENT0;893drawBuffers[1] = GL_COLOR_ATTACHMENT1;894drawBuffers[2] = GL_COLOR_ATTACHMENT2;895drawBuffers[3] = GL_NONE;896setDrawBuffers(4, drawBuffers);897}898899GLenum drawBuffers[4];900GLuint program;901GLint positionLocation;902GLint color0UniformLocation;903GLint color1UniformLocation;904GLint color2UniformLocation;905};906907// Test draw buffer state change followed draw call908TEST_P(ColorMaskForDrawBuffersTest, DrawQuad)909{910ANGLE_SKIP_TEST_IF(!setupTest());911setupColorMaskForDrawBuffersTest();912913// Draw blue into attachment0. Buffer0 should be blue and buffer1 should remain green914drawBuffers[0] = GL_COLOR_ATTACHMENT0;915setDrawBuffers(4, drawBuffers);916glUniform4fv(color0UniformLocation, 1, GLColor::blue.toNormalizedVector().data());917glUniform4fv(color1UniformLocation, 1, GLColor::cyan.toNormalizedVector().data());918glViewport(0, 0, getWindowWidth() / 2, getWindowHeight() / 2);919drawQuad(program, positionAttrib(), 0.5);920921resetDrawBuffers();922glUniform4fv(color0UniformLocation, 1, GLColor::magenta.toNormalizedVector().data());923glUniform4fv(color1UniformLocation, 1, GLColor::white.toNormalizedVector().data());924glViewport(getWindowWidth() / 2, 0, getWindowWidth() / 2, getWindowHeight() / 2);925drawQuad(program, positionAttrib(), 0.5);926EXPECT_GL_NO_ERROR();927928glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0],9290);930EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);931EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() / 4, GLColor::magenta);932EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() * 3 / 4, GLColor::red);933glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[1],9340);935EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::green);936EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() / 4, GLColor::white);937EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() * 3 / 4, GLColor::green);938EXPECT_GL_NO_ERROR();939}940941// Test draw buffer state change followed clear942TEST_P(ColorMaskForDrawBuffersTest, Clear)943{944ANGLE_SKIP_TEST_IF(!setupTest());945setupColorMaskForDrawBuffersTest();946947// Clear attachment1. Buffer0 should retain red and buffer1 should be blue948drawBuffers[1] = GL_COLOR_ATTACHMENT1;949setDrawBuffers(4, drawBuffers);950GLfloat *clearColor = GLColor::blue.toNormalizedVector().data();951glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);952glClear(GL_COLOR_BUFFER_BIT);953verifyAttachment2DColor(0, mTextures[0], GL_TEXTURE_2D, 0, GLColor::red);954verifyAttachment2DColor(1, mTextures[1], GL_TEXTURE_2D, 0, GLColor::blue);955EXPECT_GL_NO_ERROR();956}957958// Test draw buffer state change followed scissored clear959TEST_P(ColorMaskForDrawBuffersTest, ScissoredClear)960{961ANGLE_SKIP_TEST_IF(!setupTest());962setupColorMaskForDrawBuffersTest();963964// Clear attachment1. Buffer0 should retain red and buffer1 should be blue965drawBuffers[1] = GL_COLOR_ATTACHMENT1;966setDrawBuffers(4, drawBuffers);967GLfloat *clearColor = GLColor::blue.toNormalizedVector().data();968glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);969glScissor(0, 0, getWindowWidth() / 2, getWindowHeight() / 2);970glEnable(GL_SCISSOR_TEST);971glClear(GL_COLOR_BUFFER_BIT);972973resetDrawBuffers();974clearColor = GLColor::magenta.toNormalizedVector().data();975glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);976glScissor(getWindowWidth() / 2, 0, getWindowWidth() / 2, getWindowHeight() / 2);977glClear(GL_COLOR_BUFFER_BIT);978EXPECT_GL_NO_ERROR();979980glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[0],9810);982EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::red);983EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() / 4, GLColor::magenta);984EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() * 3 / 4, GLColor::red);985glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[1],9860);987EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() / 4, GLColor::blue);988EXPECT_PIXEL_COLOR_EQ(getWindowWidth() * 3 / 4, getWindowHeight() / 4, GLColor::magenta);989EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 4, getWindowHeight() * 3 / 4, GLColor::green);990EXPECT_GL_NO_ERROR();991}992993// Test draw buffer state change followed FBO blit994TEST_P(ColorMaskForDrawBuffersTest, Blit)995{996// http://anglebug.com/5284997ANGLE_SKIP_TEST_IF(IsMetal());998999ANGLE_SKIP_TEST_IF(!setupTest());1000setupColorMaskForDrawBuffersTest();10011002glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextures[2],10030);10041005// BLIT mTexture[2] to attachment0. Buffer0 should remain red and buffer1 should be yellow1006drawBuffers[0] = GL_COLOR_ATTACHMENT0;1007setDrawBuffers(4, drawBuffers);1008glBlitFramebuffer(0, 0, getWindowWidth(), getWindowHeight(), 0, 0, getWindowWidth(),1009getWindowHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST);1010verifyAttachment2DColor(0, mTextures[0], GL_TEXTURE_2D, 0, GLColor::yellow);1011verifyAttachment2DColor(1, mTextures[1], GL_TEXTURE_2D, 0, GLColor::green);1012EXPECT_GL_NO_ERROR();1013}10141015ANGLE_INSTANTIATE_TEST(DrawBuffersTest,1016ANGLE_ALL_TEST_PLATFORMS_ES2,1017ANGLE_ALL_TEST_PLATFORMS_ES3,1018WithNoTransformFeedback(ES2_VULKAN()));10191020GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DrawBuffersWebGL2Test);1021ANGLE_INSTANTIATE_TEST_ES3(DrawBuffersWebGL2Test);10221023GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DrawBuffersTestES3);1024ANGLE_INSTANTIATE_TEST_ES3(DrawBuffersTestES3);10251026GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ColorMaskForDrawBuffersTest);1027ANGLE_INSTANTIATE_TEST_ES3(ColorMaskForDrawBuffersTest);102810291030