Edit

kc3-lang/angle/src/tests/gl_tests/FramebufferFetchTest.cpp

Branch :

  • Show log

    Commit

  • Author : Shahbaz Youssefi
    Date : 2021-07-19 14:29:21
    Hash : e9decf0c
    Message : Vulkan: SPIR-V Gen: Support framebuffer fetch Bug: angleproject:4889 Change-Id: Ia75b45b5d0f6cb3b6ca8a8f8a987bb857e45ad33 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3040120 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Tim Van Patten <timvp@google.com>

  • src/tests/gl_tests/FramebufferFetchTest.cpp
  • //
    // Copyright 2021 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    // FramebufferFetchTest:
    //   Tests the correctness of the EXT_shader_framebuffer_fetch and the
    //   EXT_shader_framebuffer_fetch_non_coherent extensions.
    //
    
    #include "test_utils/ANGLETest.h"
    #include "test_utils/gl_raii.h"
    #include "util/EGLWindow.h"
    
    namespace angle
    {
    //
    // Shared Vertex Shaders for the tests below
    //
    // A 1.0 GLSL vertex shader
    static constexpr char k100VS[] = R"(#version 100
    attribute vec4 a_position;
    
    void main (void)
    {
        gl_Position = a_position;
    })";
    
    // A 3.1 GLSL vertex shader
    static constexpr char k310VS[] = R"(#version 310 es
    in highp vec4 a_position;
    
    void main (void)
    {
        gl_Position = a_position;
    })";
    
    //
    // Shared simple (i.e. no framebuffer fetch) Fragment Shaders for the tests below
    //
    // Simple (i.e. no framebuffer fetch) 3.1 GLSL fragment shader that writes to 1 attachment
    static constexpr char k310NoFetch1AttachmentFS[] = R"(#version 310 es
    layout(location = 0) out highp vec4 o_color;
    
    uniform highp vec4 u_color;
    void main (void)
    {
        o_color = u_color;
    })";
    
    //
    // Shared Coherent Fragment Shaders for the tests below
    //
    // Coherent version of a 1.0 GLSL fragment shader that uses gl_LastFragData
    static constexpr char k100CoherentFS[] = R"(#version 100
    #extension GL_EXT_shader_framebuffer_fetch : require
    mediump vec4 gl_LastFragData[gl_MaxDrawBuffers];
    uniform highp vec4 u_color;
    
    void main (void)
    {
        gl_FragColor = u_color + gl_LastFragData[0];
    })";
    
    // Coherent version of a 3.1 GLSL fragment shader that writes to 1 attachment
    static constexpr char k310Coherent1AttachmentFS[] = R"(#version 310 es
    #extension GL_EXT_shader_framebuffer_fetch : require
    layout(location = 0) inout highp vec4 o_color;
    
    uniform highp vec4 u_color;
    void main (void)
    {
        o_color += u_color;
    })";
    
    // Coherent version of a 3.1 GLSL fragment shader that writes to 4 attachments
    static constexpr char k310Coherent4AttachmentFS[] = R"(#version 310 es
    #extension GL_EXT_shader_framebuffer_fetch : require
    layout(location = 0) inout highp vec4 o_color0;
    layout(location = 1) inout highp vec4 o_color1;
    layout(location = 2) inout highp vec4 o_color2;
    layout(location = 3) inout highp vec4 o_color3;
    uniform highp vec4 u_color;
    
    void main (void)
    {
        o_color0 += u_color;
        o_color1 += u_color;
        o_color2 += u_color;
        o_color3 += u_color;
    })";
    
    // Coherent version of a 3.1 GLSL fragment shader that writes to 4 attachments via an inout
    // array
    static constexpr char k310Coherent4AttachmentArrayFS[] = R"(#version 310 es
    #extension GL_EXT_shader_framebuffer_fetch : require
    layout(location = 0) inout highp vec4 o_color[4];
    uniform highp vec4 u_color;
    
    void main (void)
    {
        o_color[0] += u_color;
        o_color[1] += u_color;
        o_color[2] += u_color;
        o_color[3] += u_color;
    })";
    
    // Coherent version of a 3.1 GLSL fragment shader that writes to 4 attachments with the order of
    // non-fetch program and fetch program with different attachments (version 1)
    static constexpr char k310CoherentDifferent4AttachmentFS1[] = R"(#version 310 es
    #extension GL_EXT_shader_framebuffer_fetch : require
    layout(location = 0) inout highp vec4 o_color0;
    layout(location = 1) out highp vec4 o_color1;
    layout(location = 2) inout highp vec4 o_color2;
    layout(location = 3) out highp vec4 o_color3;
    uniform highp vec4 u_color;
    
    void main (void)
    {
        o_color0 += u_color;
        o_color1 = u_color;
        o_color2 += u_color;
        o_color3 = u_color;
    })";
    
    // Coherent version of a 3.1 GLSL fragment shader that writes to 4 attachments with the order
    // of non-fetch program and fetch program with different attachments (version 2)
    static constexpr char k310CoherentDifferent4AttachmentFS2[] = R"(#version 310 es
    #extension GL_EXT_shader_framebuffer_fetch : require
    layout(location = 0) inout highp vec4 o_color0;
    layout(location = 1) out highp vec4 o_color1;
    layout(location = 2) out highp vec4 o_color2;
    layout(location = 3) inout highp vec4 o_color3;
    uniform highp vec4 u_color;
    
    void main (void)
    {
        o_color0 += u_color;
        o_color1 = u_color;
        o_color2 = u_color;
        o_color3 += u_color;
    })";
    
    //
    // Shared Non-Coherent Fragment Shaders for the tests below
    //
    // Non-coherent version of a 1.0 GLSL fragment shader that uses gl_LastFragData
    static constexpr char k100NonCoherentFS[] = R"(#version 100
    #extension GL_EXT_shader_framebuffer_fetch_non_coherent : require
    layout(noncoherent) mediump vec4 gl_LastFragData[gl_MaxDrawBuffers];
    uniform highp vec4 u_color;
    
    void main (void)
    {
        gl_FragColor = u_color + gl_LastFragData[0];
    })";
    
    // Non-coherent version of a 3.1 GLSL fragment shader that writes to 1 attachment
    static constexpr char k310NonCoherent1AttachmentFS[] = R"(#version 310 es
    #extension GL_EXT_shader_framebuffer_fetch_non_coherent : require
    layout(noncoherent, location = 0) inout highp vec4 o_color;
    
    uniform highp vec4 u_color;
    void main (void)
    {
        o_color += u_color;
    })";
    
    // Non-coherent version of a 3.1 GLSL fragment shader that writes to 4 attachments
    static constexpr char k310NonCoherent4AttachmentFS[] = R"(#version 310 es
    #extension GL_EXT_shader_framebuffer_fetch_non_coherent : require
    layout(noncoherent, location = 0) inout highp vec4 o_color0;
    layout(noncoherent, location = 1) inout highp vec4 o_color1;
    layout(noncoherent, location = 2) inout highp vec4 o_color2;
    layout(noncoherent, location = 3) inout highp vec4 o_color3;
    uniform highp vec4 u_color;
    
    void main (void)
    {
        o_color0 += u_color;
        o_color1 += u_color;
        o_color2 += u_color;
        o_color3 += u_color;
    })";
    
    // Non-coherent version of a 3.1 GLSL fragment shader that writes to 4 attachments via an inout
    // array
    static constexpr char k310NonCoherent4AttachmentArrayFS[] = R"(#version 310 es
    #extension GL_EXT_shader_framebuffer_fetch_non_coherent : require
    layout(noncoherent, location = 0) inout highp vec4 o_color[4];
    uniform highp vec4 u_color;
    
    void main (void)
    {
        o_color[0] += u_color;
        o_color[1] += u_color;
        o_color[2] += u_color;
        o_color[3] += u_color;
    })";
    
    // Non-coherent version of a 3.1 GLSL fragment shader that writes to 4 attachments with the order
    // of non-fetch program and fetch program with different attachments (version 1)
    static constexpr char k310NonCoherentDifferent4AttachmentFS1[] = R"(#version 310 es
    #extension GL_EXT_shader_framebuffer_fetch_non_coherent : require
    layout(noncoherent, location = 0) inout highp vec4 o_color0;
    layout(location = 1) out highp vec4 o_color1;
    layout(noncoherent, location = 2) inout highp vec4 o_color2;
    layout(location = 3) out highp vec4 o_color3;
    uniform highp vec4 u_color;
    
    void main (void)
    {
        o_color0 += u_color;
        o_color1 = u_color;
        o_color2 += u_color;
        o_color3 = u_color;
    })";
    
    // Non-coherent version of a 3.1 GLSL fragment shader that writes to 4 attachments with the order
    // of non-fetch program and fetch program with different attachments (version 2)
    static constexpr char k310NonCoherentDifferent4AttachmentFS2[] = R"(#version 310 es
    #extension GL_EXT_shader_framebuffer_fetch_non_coherent : require
    layout(noncoherent, location = 0) inout highp vec4 o_color0;
    layout(location = 1) out highp vec4 o_color1;
    layout(location = 2) out highp vec4 o_color2;
    layout(noncoherent, location = 3) inout highp vec4 o_color3;
    uniform highp vec4 u_color;
    
    void main (void)
    {
        o_color0 += u_color;
        o_color1 = u_color;
        o_color2 = u_color;
        o_color3 += u_color;
    })";
    
    class FramebufferFetchES31 : public ANGLETest
    {
      protected:
        static constexpr GLuint kMaxColorBuffer = 4u;
        static constexpr GLuint kViewportWidth  = 16u;
        static constexpr GLuint kViewportHeight = 16u;
    
        FramebufferFetchES31()
        {
            setWindowWidth(16);
            setWindowHeight(16);
            setConfigRedBits(8);
            setConfigGreenBits(8);
            setConfigBlueBits(8);
            setConfigAlphaBits(8);
            setConfigDepthBits(24);
    
            mCoherentExtension = false;
        }
    
        enum WhichExtension
        {
            COHERENT,
            NON_COHERENT,
        };
        void setWhichExtension(WhichExtension whichExtension)
        {
            mCoherentExtension = (whichExtension == COHERENT) ? true : false;
        }
    
        enum WhichFragmentShader
        {
            GLSL100,
            GLSL310_NO_FETCH_1ATTACHMENT,
            GLSL310_1ATTACHMENT,
            GLSL310_4ATTACHMENT,
            GLSL310_4ATTACHMENT_ARRAY,
            GLSL310_4ATTACHMENT_DIFFERENT1,
            GLSL310_4ATTACHMENT_DIFFERENT2,
        };
        const char *getFragmentShader(WhichFragmentShader whichFragmentShader)
        {
            if (mCoherentExtension)
            {
                switch (whichFragmentShader)
                {
                    case GLSL100:
                        return k100CoherentFS;
                    case GLSL310_NO_FETCH_1ATTACHMENT:
                        return k310NoFetch1AttachmentFS;
                    case GLSL310_1ATTACHMENT:
                        return k310Coherent1AttachmentFS;
                    case GLSL310_4ATTACHMENT:
                        return k310Coherent4AttachmentFS;
                    case GLSL310_4ATTACHMENT_ARRAY:
                        return k310Coherent4AttachmentArrayFS;
                    case GLSL310_4ATTACHMENT_DIFFERENT1:
                        return k310CoherentDifferent4AttachmentFS1;
                    case GLSL310_4ATTACHMENT_DIFFERENT2:
                        return k310CoherentDifferent4AttachmentFS2;
                }
            }
            else
            {
                switch (whichFragmentShader)
                {
                    case GLSL100:
                        return k100NonCoherentFS;
                    case GLSL310_NO_FETCH_1ATTACHMENT:
                        return k310NoFetch1AttachmentFS;
                    case GLSL310_1ATTACHMENT:
                        return k310NonCoherent1AttachmentFS;
                    case GLSL310_4ATTACHMENT:
                        return k310NonCoherent4AttachmentFS;
                    case GLSL310_4ATTACHMENT_ARRAY:
                        return k310NonCoherent4AttachmentArrayFS;
                    case GLSL310_4ATTACHMENT_DIFFERENT1:
                        return k310NonCoherentDifferent4AttachmentFS1;
                    case GLSL310_4ATTACHMENT_DIFFERENT2:
                        return k310NonCoherentDifferent4AttachmentFS2;
                }
            }
        }
    
        void render(GLuint coordLoc, GLboolean needsFramebufferFetchBarrier)
        {
            const GLfloat coords[] = {
                -1.0f, -1.0f, +1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f,
            };
    
            const GLushort indices[] = {
                0, 1, 2, 2, 3, 0,
            };
    
            glViewport(0, 0, kViewportWidth, kViewportHeight);
    
            GLBuffer coordinatesBuffer;
            GLBuffer elementsBuffer;
    
            glBindBuffer(GL_ARRAY_BUFFER, coordinatesBuffer);
            glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)sizeof(coords), coords, GL_STATIC_DRAW);
            glEnableVertexAttribArray(coordLoc);
            glVertexAttribPointer(coordLoc, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
    
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementsBuffer);
            glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)sizeof(indices), &indices[0],
                         GL_STATIC_DRAW);
    
            if (needsFramebufferFetchBarrier)
            {
                glFramebufferFetchBarrierEXT();
            }
    
            glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
    
            ASSERT_GL_NO_ERROR();
        }
    
        void BasicTest(GLProgram program)
        {
            GLFramebuffer framebuffer;
            glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
            std::vector<GLColor> greenColor(kViewportWidth * kViewportHeight, GLColor::green);
            GLTexture colorBufferTex;
            glBindTexture(GL_TEXTURE_2D, colorBufferTex);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, greenColor.data());
            glBindTexture(GL_TEXTURE_2D, 0);
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBufferTex,
                                   0);
    
            ASSERT_GL_NO_ERROR();
    
            float color[4]      = {1.0f, 0.0f, 0.0f, 1.0f};
            GLint colorLocation = glGetUniformLocation(program, "u_color");
            glUniform4fv(colorLocation, 1, color);
    
            GLint positionLocation = glGetAttribLocation(program, "a_position");
            render(positionLocation, !mCoherentExtension);
    
            ASSERT_GL_NO_ERROR();
    
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
    
            glBindFramebuffer(GL_FRAMEBUFFER, 0);
        }
    
        void MultipleRenderTargetTest(GLProgram program)
        {
            GLFramebuffer framebuffer;
            glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
            std::vector<GLColor> color0(kViewportWidth * kViewportHeight, GLColor::black);
            std::vector<GLColor> color1(kViewportWidth * kViewportHeight, GLColor::green);
            std::vector<GLColor> color2(kViewportWidth * kViewportHeight, GLColor::blue);
            std::vector<GLColor> color3(kViewportWidth * kViewportHeight, GLColor::cyan);
            GLTexture colorBufferTex[kMaxColorBuffer];
            GLenum colorAttachments[kMaxColorBuffer] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
                                                        GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3};
            glBindTexture(GL_TEXTURE_2D, colorBufferTex[0]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, color0.data());
            glBindTexture(GL_TEXTURE_2D, colorBufferTex[1]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, color1.data());
            glBindTexture(GL_TEXTURE_2D, colorBufferTex[2]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, color2.data());
            glBindTexture(GL_TEXTURE_2D, colorBufferTex[3]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, color3.data());
            glBindTexture(GL_TEXTURE_2D, 0);
            for (unsigned int i = 0; i < kMaxColorBuffer; i++)
            {
                glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[i], GL_TEXTURE_2D,
                                       colorBufferTex[i], 0);
            }
            glDrawBuffers(kMaxColorBuffer, &colorAttachments[0]);
    
            ASSERT_GL_NO_ERROR();
    
            float color[4]      = {1.0f, 0.0f, 0.0f, 1.0f};
            GLint colorLocation = glGetUniformLocation(program, "u_color");
            glUniform4fv(colorLocation, 1, color);
    
            GLint positionLocation = glGetAttribLocation(program, "a_position");
            render(positionLocation, !mCoherentExtension);
    
            ASSERT_GL_NO_ERROR();
    
            glReadBuffer(colorAttachments[0]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
            glReadBuffer(colorAttachments[1]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
            glReadBuffer(colorAttachments[2]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::magenta);
            glReadBuffer(colorAttachments[3]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::white);
    
            glBindFramebuffer(GL_FRAMEBUFFER, 0);
        }
    
        void MultipleRenderTargetArrayTest(GLProgram program)
        {
            GLFramebuffer framebuffer;
            glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
            std::vector<GLColor> color0(kViewportWidth * kViewportHeight, GLColor::black);
            std::vector<GLColor> color1(kViewportWidth * kViewportHeight, GLColor::green);
            std::vector<GLColor> color2(kViewportWidth * kViewportHeight, GLColor::blue);
            std::vector<GLColor> color3(kViewportWidth * kViewportHeight, GLColor::cyan);
            GLTexture colorBufferTex[kMaxColorBuffer];
            GLenum colorAttachments[kMaxColorBuffer] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
                                                        GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3};
            glBindTexture(GL_TEXTURE_2D, colorBufferTex[0]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, color0.data());
            glBindTexture(GL_TEXTURE_2D, colorBufferTex[1]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, color1.data());
            glBindTexture(GL_TEXTURE_2D, colorBufferTex[2]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, color2.data());
            glBindTexture(GL_TEXTURE_2D, colorBufferTex[3]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, color3.data());
            glBindTexture(GL_TEXTURE_2D, 0);
            for (unsigned int i = 0; i < kMaxColorBuffer; i++)
            {
                glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[i], GL_TEXTURE_2D,
                                       colorBufferTex[i], 0);
            }
            glDrawBuffers(kMaxColorBuffer, &colorAttachments[0]);
    
            ASSERT_GL_NO_ERROR();
    
            float color[4]      = {1.0f, 0.0f, 0.0f, 1.0f};
            GLint colorLocation = glGetUniformLocation(program, "u_color");
            glUniform4fv(colorLocation, 1, color);
    
            GLint positionLocation = glGetAttribLocation(program, "a_position");
            render(positionLocation, !mCoherentExtension);
    
            ASSERT_GL_NO_ERROR();
    
            glReadBuffer(colorAttachments[0]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
            glReadBuffer(colorAttachments[1]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
            glReadBuffer(colorAttachments[2]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::magenta);
            glReadBuffer(colorAttachments[3]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::white);
    
            glBindFramebuffer(GL_FRAMEBUFFER, 0);
        }
    
        void MultipleDrawTest(GLProgram program)
        {
            GLFramebuffer framebuffer;
            glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
            std::vector<GLColor> greenColor(kViewportWidth * kViewportHeight, GLColor::green);
            GLTexture colorBufferTex;
            glBindTexture(GL_TEXTURE_2D, colorBufferTex);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, greenColor.data());
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBufferTex,
                                   0);
    
            ASSERT_GL_NO_ERROR();
    
            float color1[4]     = {1.0f, 0.0f, 0.0f, 1.0f};
            GLint colorLocation = glGetUniformLocation(program, "u_color");
            glUniform4fv(colorLocation, 1, color1);
    
            GLint positionLocation = glGetAttribLocation(program, "a_position");
            render(positionLocation, !mCoherentExtension);
    
            float color2[4] = {0.0f, 0.0f, 1.0f, 1.0f};
            glUniform4fv(colorLocation, 1, color2);
    
            render(positionLocation, !mCoherentExtension);
    
            ASSERT_GL_NO_ERROR();
    
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::white);
    
            glBindFramebuffer(GL_FRAMEBUFFER, 0);
        }
    
        void DrawNonFetchDrawFetchTest(GLProgram programNonFetch, GLProgram programFetch)
        {
            glUseProgram(programNonFetch);
            ASSERT_GL_NO_ERROR();
    
            GLFramebuffer framebuffer;
            glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
            std::vector<GLColor> greenColor(kViewportWidth * kViewportHeight, GLColor::green);
            GLTexture colorBufferTex;
            glBindTexture(GL_TEXTURE_2D, colorBufferTex);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, greenColor.data());
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBufferTex,
                                   0);
    
            ASSERT_GL_NO_ERROR();
    
            float colorRed[4]           = {1.0f, 0.0f, 0.0f, 1.0f};
            GLint colorLocationNonFetch = glGetUniformLocation(programNonFetch, "u_color");
            glUniform4fv(colorLocationNonFetch, 1, colorRed);
    
            GLint positionLocationNonFetch = glGetAttribLocation(programNonFetch, "a_position");
            // Render without regard to glFramebufferFetchBarrierEXT()
            render(positionLocationNonFetch, GL_FALSE);
    
            ASSERT_GL_NO_ERROR();
    
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
    
            glUseProgram(programFetch);
    
            float colorGreen[4]      = {0.0f, 1.0f, 0.0f, 1.0f};
            GLint colorLocationFetch = glGetUniformLocation(programFetch, "u_color");
            glUniform4fv(colorLocationFetch, 1, colorGreen);
    
            GLint positionLocationFetch = glGetAttribLocation(programFetch, "a_position");
            // Render potentially with a glFramebufferFetchBarrierEXT() depending on the [non-]coherent
            // extension being used
            render(positionLocationFetch, !mCoherentExtension);
    
            ASSERT_GL_NO_ERROR();
    
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
    
            glUseProgram(programNonFetch);
            glUniform4fv(colorLocationNonFetch, 1, colorRed);
            // Render without regard to glFramebufferFetchBarrierEXT()
            render(positionLocationNonFetch, GL_FALSE);
    
            ASSERT_GL_NO_ERROR();
    
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
    
            glUseProgram(programFetch);
            glUniform4fv(colorLocationFetch, 1, colorGreen);
            // Render potentially with a glFramebufferFetchBarrierEXT() depending on the [non-]coherent
            // extension being used
            render(positionLocationFetch, !mCoherentExtension);
    
            ASSERT_GL_NO_ERROR();
    
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
    
            glBindFramebuffer(GL_FRAMEBUFFER, 0);
        }
    
        void DrawFetchDrawNonFetchTest(GLProgram programNonFetch, GLProgram programFetch)
        {
            glUseProgram(programFetch);
            ASSERT_GL_NO_ERROR();
    
            GLFramebuffer framebuffer;
            glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
            std::vector<GLColor> greenColor(kViewportWidth * kViewportHeight, GLColor::green);
            GLTexture colorBufferTex;
            glBindTexture(GL_TEXTURE_2D, colorBufferTex);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, greenColor.data());
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBufferTex,
                                   0);
    
            ASSERT_GL_NO_ERROR();
    
            float colorRed[4]        = {1.0f, 0.0f, 0.0f, 1.0f};
            GLint colorLocationFetch = glGetUniformLocation(programFetch, "u_color");
            glUniform4fv(colorLocationFetch, 1, colorRed);
    
            GLint positionLocationFetch = glGetAttribLocation(programFetch, "a_position");
            // Render potentially with a glFramebufferFetchBarrierEXT() depending on the [non-]coherent
            // extension being used
            render(positionLocationFetch, !mCoherentExtension);
            ASSERT_GL_NO_ERROR();
    
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
    
            glUseProgram(programNonFetch);
    
            GLint colorLocationNonFetch = glGetUniformLocation(programNonFetch, "u_color");
            glUniform4fv(colorLocationNonFetch, 1, colorRed);
    
            GLint positionLocationNonFetch = glGetAttribLocation(programNonFetch, "a_position");
            // Render without regard to glFramebufferFetchBarrierEXT()
            render(positionLocationNonFetch, GL_FALSE);
            ASSERT_GL_NO_ERROR();
    
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
    
            float colorGreen[4] = {0.0f, 1.0f, 0.0f, 1.0f};
            glUseProgram(programFetch);
            glUniform4fv(colorLocationFetch, 1, colorGreen);
            // Render potentially with a glFramebufferFetchBarrierEXT() depending on the [non-]coherent
            // extension being used
            render(positionLocationFetch, !mCoherentExtension);
            ASSERT_GL_NO_ERROR();
    
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
    
            glUseProgram(programNonFetch);
            glUniform4fv(colorLocationNonFetch, 1, colorRed);
            // Render without regard to glFramebufferFetchBarrierEXT()
            render(positionLocationNonFetch, GL_FALSE);
    
            ASSERT_GL_NO_ERROR();
    
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
    
            glBindFramebuffer(GL_FRAMEBUFFER, 0);
        }
    
        void DrawNonFetchDrawFetchWithDifferentAttachmentsTest(GLProgram programNonFetch,
                                                               GLProgram programFetch)
        {
            glUseProgram(programNonFetch);
            ASSERT_GL_NO_ERROR();
    
            GLFramebuffer framebuffer;
            glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
            std::vector<GLColor> greenColor(kViewportWidth * kViewportHeight, GLColor::green);
            GLTexture colorTex;
            glBindTexture(GL_TEXTURE_2D, colorTex);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, greenColor.data());
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0);
    
            ASSERT_GL_NO_ERROR();
    
            float colorRed[4]           = {1.0f, 0.0f, 0.0f, 1.0f};
            GLint colorLocationNonFetch = glGetUniformLocation(programNonFetch, "u_color");
            glUniform4fv(colorLocationNonFetch, 1, colorRed);
    
            GLint positionLocationNonFetch = glGetAttribLocation(programNonFetch, "a_position");
            // Render without regard to glFramebufferFetchBarrierEXT()
            render(positionLocationNonFetch, GL_FALSE);
            ASSERT_GL_NO_ERROR();
    
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
    
            glUseProgram(programFetch);
            ASSERT_GL_NO_ERROR();
    
            GLFramebuffer framebufferMRT1;
            glBindFramebuffer(GL_FRAMEBUFFER, framebufferMRT1);
            std::vector<GLColor> color1(kViewportWidth * kViewportHeight, GLColor::green);
            std::vector<GLColor> color2(kViewportWidth * kViewportHeight, GLColor::blue);
            GLTexture colorBufferTex1[kMaxColorBuffer];
            GLenum colorAttachments[kMaxColorBuffer] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
                                                        GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3};
            glBindTexture(GL_TEXTURE_2D, colorBufferTex1[0]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, color1.data());
            glBindTexture(GL_TEXTURE_2D, colorBufferTex1[1]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, color1.data());
            glBindTexture(GL_TEXTURE_2D, colorBufferTex1[2]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, color2.data());
            glBindTexture(GL_TEXTURE_2D, colorBufferTex1[3]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, color2.data());
            glBindTexture(GL_TEXTURE_2D, 0);
            for (unsigned int i = 0; i < kMaxColorBuffer; i++)
            {
                glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[i], GL_TEXTURE_2D,
                                       colorBufferTex1[i], 0);
            }
            glDrawBuffers(kMaxColorBuffer, &colorAttachments[0]);
            ASSERT_GL_NO_ERROR();
    
            GLint colorLocation = glGetUniformLocation(programFetch, "u_color");
            glUniform4fv(colorLocation, 1, colorRed);
    
            GLint positionLocation = glGetAttribLocation(programFetch, "a_position");
            // Render potentially with a glFramebufferFetchBarrierEXT() depending on the [non-]coherent
            // extension being used
            render(positionLocation, !mCoherentExtension);
            ASSERT_GL_NO_ERROR();
    
            glReadBuffer(colorAttachments[0]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
            glReadBuffer(colorAttachments[1]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
            glReadBuffer(colorAttachments[2]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::magenta);
            glReadBuffer(colorAttachments[3]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
    
            GLFramebuffer framebufferMRT2;
            glBindFramebuffer(GL_FRAMEBUFFER, framebufferMRT2);
            GLTexture colorBufferTex2[kMaxColorBuffer];
            glBindTexture(GL_TEXTURE_2D, colorBufferTex2[0]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, color2.data());
            glBindTexture(GL_TEXTURE_2D, colorBufferTex2[1]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, color2.data());
            glBindTexture(GL_TEXTURE_2D, colorBufferTex2[2]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, color1.data());
            glBindTexture(GL_TEXTURE_2D, colorBufferTex2[3]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, color1.data());
            glBindTexture(GL_TEXTURE_2D, 0);
            for (unsigned int i = 0; i < kMaxColorBuffer; i++)
            {
                glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[i], GL_TEXTURE_2D,
                                       colorBufferTex2[i], 0);
            }
            glDrawBuffers(kMaxColorBuffer, &colorAttachments[0]);
            ASSERT_GL_NO_ERROR();
    
            glUniform4fv(colorLocation, 1, colorRed);
            // Render potentially with a glFramebufferFetchBarrierEXT() depending on the [non-]coherent
            // extension being used
            render(positionLocation, !mCoherentExtension);
            ASSERT_GL_NO_ERROR();
    
            glReadBuffer(colorAttachments[0]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::magenta);
            glReadBuffer(colorAttachments[1]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
            glReadBuffer(colorAttachments[2]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
            glReadBuffer(colorAttachments[3]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
    
            glBindFramebuffer(GL_FRAMEBUFFER, 0);
        }
    
        void DrawNonFetchDrawFetchWithDifferentProgramsTest(GLProgram programNonFetch,
                                                            GLProgram programFetch1,
                                                            GLProgram programFetch2)
        {
            glUseProgram(programNonFetch);
            ASSERT_GL_NO_ERROR();
            GLFramebuffer framebuffer;
            glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
            std::vector<GLColor> greenColor(kViewportWidth * kViewportHeight, GLColor::green);
            GLTexture colorTex;
            glBindTexture(GL_TEXTURE_2D, colorTex);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, greenColor.data());
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0);
    
            ASSERT_GL_NO_ERROR();
    
            float colorRed[4]           = {1.0f, 0.0f, 0.0f, 1.0f};
            GLint colorLocationNonFetch = glGetUniformLocation(programNonFetch, "u_color");
            glUniform4fv(colorLocationNonFetch, 1, colorRed);
    
            GLint positionLocationNonFetch = glGetAttribLocation(programNonFetch, "a_position");
            // Render without regard to glFramebufferFetchBarrierEXT()
            render(positionLocationNonFetch, GL_FALSE);
            ASSERT_GL_NO_ERROR();
    
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
    
            glUseProgram(programFetch1);
            ASSERT_GL_NO_ERROR();
    
            GLFramebuffer framebufferMRT1;
            glBindFramebuffer(GL_FRAMEBUFFER, framebufferMRT1);
            std::vector<GLColor> color1(kViewportWidth * kViewportHeight, GLColor::green);
            GLTexture colorBufferTex1[kMaxColorBuffer];
            GLenum colorAttachments[kMaxColorBuffer] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
                                                        GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3};
            glBindTexture(GL_TEXTURE_2D, colorBufferTex1[0]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, color1.data());
            glBindTexture(GL_TEXTURE_2D, colorBufferTex1[1]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, color1.data());
            glBindTexture(GL_TEXTURE_2D, colorBufferTex1[2]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, color1.data());
            glBindTexture(GL_TEXTURE_2D, colorBufferTex1[3]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, color1.data());
            glBindTexture(GL_TEXTURE_2D, 0);
            for (unsigned int i = 0; i < kMaxColorBuffer; i++)
            {
                glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[i], GL_TEXTURE_2D,
                                       colorBufferTex1[i], 0);
            }
            glDrawBuffers(kMaxColorBuffer, &colorAttachments[0]);
            ASSERT_GL_NO_ERROR();
    
            GLint colorLocation = glGetUniformLocation(programFetch1, "u_color");
            glUniform4fv(colorLocation, 1, colorRed);
    
            GLint positionLocation = glGetAttribLocation(programFetch1, "a_position");
            // Render potentially with a glFramebufferFetchBarrierEXT() depending on the [non-]coherent
            // extension being used
            render(positionLocation, !mCoherentExtension);
            ASSERT_GL_NO_ERROR();
    
            glReadBuffer(colorAttachments[0]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
            glReadBuffer(colorAttachments[1]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
            glReadBuffer(colorAttachments[2]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
            glReadBuffer(colorAttachments[3]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
    
            glUseProgram(programFetch2);
            ASSERT_GL_NO_ERROR();
    
            glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT);
    
            GLint colorLocation1 = glGetUniformLocation(programFetch2, "u_color");
            glUniform4fv(colorLocation1, 1, colorRed);
    
            GLint positionLocation1 = glGetAttribLocation(programFetch2, "a_position");
            // Render potentially with a glFramebufferFetchBarrierEXT() depending on the [non-]coherent
            // extension being used
            render(positionLocation1, !mCoherentExtension);
            ASSERT_GL_NO_ERROR();
    
            glReadBuffer(colorAttachments[0]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
            glReadBuffer(colorAttachments[1]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
            glReadBuffer(colorAttachments[2]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
            glReadBuffer(colorAttachments[3]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
    
            glBindFramebuffer(GL_FRAMEBUFFER, 0);
        }
    
        void DrawFetchBlitDrawFetchTest(GLProgram programNonFetch, GLProgram programFetch)
        {
            glUseProgram(programFetch);
            ASSERT_GL_NO_ERROR();
    
            GLFramebuffer framebufferMRT1;
            glBindFramebuffer(GL_FRAMEBUFFER, framebufferMRT1);
            std::vector<GLColor> color1(kViewportWidth * kViewportHeight, GLColor::green);
            std::vector<GLColor> color2(kViewportWidth * kViewportHeight, GLColor::blue);
            GLTexture colorBufferTex1[kMaxColorBuffer];
            GLenum colorAttachments[kMaxColorBuffer] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
                                                        GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3};
            glBindTexture(GL_TEXTURE_2D, colorBufferTex1[0]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, color1.data());
            glBindTexture(GL_TEXTURE_2D, colorBufferTex1[1]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, color1.data());
            glBindTexture(GL_TEXTURE_2D, colorBufferTex1[2]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, color2.data());
            glBindTexture(GL_TEXTURE_2D, colorBufferTex1[3]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, color2.data());
            glBindTexture(GL_TEXTURE_2D, 0);
            for (unsigned int i = 0; i < kMaxColorBuffer; i++)
            {
                glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[i], GL_TEXTURE_2D,
                                       colorBufferTex1[i], 0);
            }
            glDrawBuffers(kMaxColorBuffer, &colorAttachments[0]);
            ASSERT_GL_NO_ERROR();
    
            float colorRed[4]   = {1.0f, 0.0f, 0.0f, 1.0f};
            GLint colorLocation = glGetUniformLocation(programFetch, "u_color");
            glUniform4fv(colorLocation, 1, colorRed);
    
            GLint positionLocation = glGetAttribLocation(programFetch, "a_position");
            // Render potentially with a glFramebufferFetchBarrierEXT() depending on the [non-]coherent
            // extension being used
            render(positionLocation, !mCoherentExtension);
            ASSERT_GL_NO_ERROR();
    
            glReadBuffer(colorAttachments[0]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
            glReadBuffer(colorAttachments[1]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
            glReadBuffer(colorAttachments[2]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::magenta);
            glReadBuffer(colorAttachments[3]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
    
            GLFramebuffer framebufferColor;
            glBindFramebuffer(GL_FRAMEBUFFER, framebufferColor);
    
            GLTexture colorTex;
            glBindTexture(GL_TEXTURE_2D, colorTex);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, color2.data());
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0);
    
            glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, framebufferColor);
            glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, framebufferMRT1);
    
            glBlitFramebuffer(0, 0, kViewportWidth, kViewportHeight, 0, 0, kViewportWidth,
                              kViewportHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
            ASSERT_GL_NO_ERROR();
    
            glBindFramebuffer(GL_FRAMEBUFFER, framebufferMRT1);
            glReadBuffer(colorAttachments[0]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::blue);
            glReadBuffer(colorAttachments[1]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::blue);
            glReadBuffer(colorAttachments[2]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::blue);
            glReadBuffer(colorAttachments[3]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::blue);
    
            float colorGreen[4] = {0.0f, 1.0f, 0.0f, 1.0f};
            glUniform4fv(colorLocation, 1, colorGreen);
    
            // Render potentially with a glFramebufferFetchBarrierEXT() depending on the [non-]coherent
            // extension being used
            render(positionLocation, !mCoherentExtension);
            ASSERT_GL_NO_ERROR();
    
            glReadBuffer(colorAttachments[0]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::cyan);
            glReadBuffer(colorAttachments[1]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::green);
            glReadBuffer(colorAttachments[2]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::cyan);
            glReadBuffer(colorAttachments[3]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::green);
    
            glBindFramebuffer(GL_FRAMEBUFFER, 0);
        }
    
        void ProgramPipelineTest(const char *kVS, const char *kFS1, const char *kFS2)
        {
            GLProgram programVert, programNonFetch, programFetch;
            const char *sourceArray[3] = {kVS, kFS1, kFS2};
    
            GLShader vertShader(GL_VERTEX_SHADER);
            glShaderSource(vertShader, 1, &sourceArray[0], nullptr);
            glCompileShader(vertShader);
            glProgramParameteri(programVert, GL_PROGRAM_SEPARABLE, GL_TRUE);
            glAttachShader(programVert, vertShader);
            glLinkProgram(programVert);
            ASSERT_GL_NO_ERROR();
    
            GLShader fragShader1(GL_FRAGMENT_SHADER);
            glShaderSource(fragShader1, 1, &sourceArray[1], nullptr);
            glCompileShader(fragShader1);
            glProgramParameteri(programNonFetch, GL_PROGRAM_SEPARABLE, GL_TRUE);
            glAttachShader(programNonFetch, fragShader1);
            glLinkProgram(programNonFetch);
            ASSERT_GL_NO_ERROR();
    
            GLShader fragShader2(GL_FRAGMENT_SHADER);
            glShaderSource(fragShader2, 1, &sourceArray[2], nullptr);
            glCompileShader(fragShader2);
            glProgramParameteri(programFetch, GL_PROGRAM_SEPARABLE, GL_TRUE);
            glAttachShader(programFetch, fragShader2);
            glLinkProgram(programFetch);
            ASSERT_GL_NO_ERROR();
    
            GLProgramPipeline pipeline1, pipeline2, pipeline3, pipeline4;
            glUseProgramStages(pipeline1, GL_VERTEX_SHADER_BIT, programVert);
            glUseProgramStages(pipeline1, GL_FRAGMENT_SHADER_BIT, programNonFetch);
            glBindProgramPipeline(pipeline1);
            ASSERT_GL_NO_ERROR();
    
            GLFramebuffer framebuffer;
            glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
            std::vector<GLColor> greenColor(kViewportWidth * kViewportHeight, GLColor::green);
            GLTexture colorBufferTex;
            glBindTexture(GL_TEXTURE_2D, colorBufferTex);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, greenColor.data());
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBufferTex,
                                   0);
            ASSERT_GL_NO_ERROR();
    
            glActiveShaderProgram(pipeline1, programNonFetch);
            float colorRed[4]           = {1.0f, 0.0f, 0.0f, 1.0f};
            GLint colorLocationNonFetch = glGetUniformLocation(programNonFetch, "u_color");
            glUniform4fv(colorLocationNonFetch, 1, colorRed);
            ASSERT_GL_NO_ERROR();
    
            glActiveShaderProgram(pipeline1, programVert);
            GLint positionLocation = glGetAttribLocation(programVert, "a_position");
            // Render without regard to glFramebufferFetchBarrierEXT()
            render(positionLocation, GL_FALSE);
            ASSERT_GL_NO_ERROR();
    
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
    
            glUseProgramStages(pipeline2, GL_VERTEX_SHADER_BIT, programVert);
            glUseProgramStages(pipeline2, GL_FRAGMENT_SHADER_BIT, programFetch);
            glBindProgramPipeline(pipeline2);
            ASSERT_GL_NO_ERROR();
    
            glActiveShaderProgram(pipeline2, programFetch);
            float colorGreen[4]      = {0.0f, 1.0f, 0.0f, 1.0f};
            GLint colorLocationFetch = glGetUniformLocation(programFetch, "u_color");
            glUniform4fv(colorLocationFetch, 1, colorGreen);
    
            // Render potentially with a glFramebufferFetchBarrierEXT() depending on the [non-]coherent
            // extension being used
            render(positionLocation, !mCoherentExtension);
            ASSERT_GL_NO_ERROR();
    
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
    
            glUseProgramStages(pipeline3, GL_VERTEX_SHADER_BIT, programVert);
            glUseProgramStages(pipeline3, GL_FRAGMENT_SHADER_BIT, programNonFetch);
            glBindProgramPipeline(pipeline3);
            ASSERT_GL_NO_ERROR();
    
            glActiveShaderProgram(pipeline3, programNonFetch);
            colorLocationNonFetch = glGetUniformLocation(programNonFetch, "u_color");
            glUniform4fv(colorLocationNonFetch, 1, colorRed);
    
            ASSERT_GL_NO_ERROR();
    
            // Render without regard to glFramebufferFetchBarrierEXT()
            render(positionLocation, GL_FALSE);
            ASSERT_GL_NO_ERROR();
    
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::red);
    
            glUseProgramStages(pipeline4, GL_VERTEX_SHADER_BIT, programVert);
            glUseProgramStages(pipeline4, GL_FRAGMENT_SHADER_BIT, programFetch);
            glBindProgramPipeline(pipeline4);
            ASSERT_GL_NO_ERROR();
    
            glActiveShaderProgram(pipeline4, programFetch);
            colorLocationFetch = glGetUniformLocation(programFetch, "u_color");
            glUniform4fv(colorLocationFetch, 1, colorGreen);
            // Render potentially with a glFramebufferFetchBarrierEXT() depending on the [non-]coherent
            // extension being used
            render(positionLocation, !mCoherentExtension);
            ASSERT_GL_NO_ERROR();
    
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
    
            glBindFramebuffer(GL_FRAMEBUFFER, 0);
        }
    
        bool mCoherentExtension;
    };
    
    // Test coherent extension with inout qualifier
    TEST_P(FramebufferFetchES31, BasicInout_Coherent)
    {
        ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
        setWhichExtension(COHERENT);
    
        GLProgram program;
        program.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT));
        glUseProgram(program);
        ASSERT_GL_NO_ERROR();
    
        BasicTest(program);
    }
    
    // Test non-coherent extension with inout qualifier
    TEST_P(FramebufferFetchES31, BasicInout_NonCoherent)
    {
        ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
        setWhichExtension(NON_COHERENT);
    
        GLProgram program;
        program.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT));
        glUseProgram(program);
        ASSERT_GL_NO_ERROR();
    
        BasicTest(program);
    }
    
    // Test coherent extension with gl_LastFragData
    TEST_P(FramebufferFetchES31, BasicLastFragData_Coherent)
    {
        ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
        setWhichExtension(COHERENT);
    
        GLProgram program;
        program.makeRaster(k100VS, getFragmentShader(GLSL100));
        glUseProgram(program);
        ASSERT_GL_NO_ERROR();
    
        BasicTest(program);
    }
    
    // Test non-coherent extension with gl_LastFragData
    TEST_P(FramebufferFetchES31, BasicLastFragData_NonCoherent)
    {
        ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
        setWhichExtension(NON_COHERENT);
    
        GLProgram program;
        program.makeRaster(k100VS, getFragmentShader(GLSL100));
        glUseProgram(program);
        ASSERT_GL_NO_ERROR();
    
        BasicTest(program);
    }
    
    // Testing coherent extension with multiple render target
    TEST_P(FramebufferFetchES31, MultipleRenderTarget_Coherent)
    {
        ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
        setWhichExtension(COHERENT);
    
        GLProgram program;
        program.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT));
        glUseProgram(program);
        ASSERT_GL_NO_ERROR();
    
        MultipleRenderTargetTest(program);
    }
    
    // Testing non-coherent extension with multiple render target
    TEST_P(FramebufferFetchES31, MultipleRenderTarget_NonCoherent)
    {
        ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
        setWhichExtension(NON_COHERENT);
    
        GLProgram program;
        program.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT));
        glUseProgram(program);
        ASSERT_GL_NO_ERROR();
    
        MultipleRenderTargetTest(program);
    }
    
    // Testing non-coherent extension with multiple render target using inout array
    TEST_P(FramebufferFetchES31, MultipleRenderTargetWithInoutArray_NonCoherent)
    {
        ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
        setWhichExtension(NON_COHERENT);
    
        GLProgram program;
        program.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT));
        glUseProgram(program);
        ASSERT_GL_NO_ERROR();
    
        MultipleRenderTargetTest(program);
    }
    
    // Testing coherent extension with multiple render target using inout array
    TEST_P(FramebufferFetchES31, MultipleRenderTargetWithInoutArray_Coherent)
    {
        ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
        setWhichExtension(COHERENT);
    
        GLProgram program;
        program.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT));
        glUseProgram(program);
        ASSERT_GL_NO_ERROR();
    
        MultipleRenderTargetTest(program);
    }
    
    // Test coherent extension with multiple draw
    TEST_P(FramebufferFetchES31, MultipleDraw_Coherent)
    {
        ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
        setWhichExtension(COHERENT);
    
        GLProgram program;
        program.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT));
        glUseProgram(program);
        ASSERT_GL_NO_ERROR();
    
        MultipleDrawTest(program);
    }
    
    // Test non-coherent extension with multiple draw
    TEST_P(FramebufferFetchES31, MultipleDraw_NonCoherent)
    {
        ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
        setWhichExtension(NON_COHERENT);
    
        GLProgram program;
        program.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT));
        glUseProgram(program);
        ASSERT_GL_NO_ERROR();
    
        MultipleDrawTest(program);
    }
    
    // Testing coherent extension with the order of non-fetch program and fetch program
    TEST_P(FramebufferFetchES31, DrawNonFetchDrawFetch_Coherent)
    {
        ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
        setWhichExtension(COHERENT);
    
        GLProgram programNonFetch, programFetch;
        programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
        programFetch.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT));
        ASSERT_GL_NO_ERROR();
    
        DrawNonFetchDrawFetchTest(programNonFetch, programFetch);
    }
    
    // Testing non-coherent extension with the order of non-fetch program and fetch program
    TEST_P(FramebufferFetchES31, DrawNonFetchDrawFetch_NonCoherent)
    {
        ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
        setWhichExtension(NON_COHERENT);
    
        GLProgram programNonFetch, programFetch;
        programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
        programFetch.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT));
        ASSERT_GL_NO_ERROR();
    
        DrawNonFetchDrawFetchTest(programNonFetch, programFetch);
    }
    
    // Testing coherent extension with the order of fetch program and non-fetch program
    TEST_P(FramebufferFetchES31, DrawFetchDrawNonFetch_Coherent)
    {
        ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
        setWhichExtension(COHERENT);
    
        GLProgram programNonFetch, programFetch;
        programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
        programFetch.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT));
        ASSERT_GL_NO_ERROR();
    
        DrawFetchDrawNonFetchTest(programNonFetch, programFetch);
    }
    
    // Testing non-coherent extension with the order of fetch program and non-fetch program
    TEST_P(FramebufferFetchES31, DrawFetchDrawNonFetch_NonCoherent)
    {
        ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
        setWhichExtension(NON_COHERENT);
    
        GLProgram programNonFetch, programFetch;
        programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
        programFetch.makeRaster(k310VS, getFragmentShader(GLSL310_1ATTACHMENT));
        ASSERT_GL_NO_ERROR();
    
        DrawFetchDrawNonFetchTest(programNonFetch, programFetch);
    }
    
    // Testing coherent extension with the order of non-fetch program and fetch program with
    // different attachments
    TEST_P(FramebufferFetchES31, DrawNonFetchDrawFetchWithDifferentAttachments_Coherent)
    {
        ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
        setWhichExtension(COHERENT);
    
        GLProgram programNonFetch, programFetch;
        programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
        programFetch.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT_DIFFERENT1));
        ASSERT_GL_NO_ERROR();
    
        DrawNonFetchDrawFetchWithDifferentAttachmentsTest(programNonFetch, programFetch);
    }
    
    // Testing non-coherent extension with the order of non-fetch program and fetch program with
    // different attachments
    TEST_P(FramebufferFetchES31, DrawNonFetchDrawFetchWithDifferentAttachments_NonCoherent)
    {
        ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
        setWhichExtension(NON_COHERENT);
    
        GLProgram programNonFetch, programFetch;
        programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
        programFetch.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT_DIFFERENT1));
        ASSERT_GL_NO_ERROR();
    
        DrawNonFetchDrawFetchWithDifferentAttachmentsTest(programNonFetch, programFetch);
    }
    
    // Testing coherent extension with the order of non-fetch program and fetch with different
    // programs
    TEST_P(FramebufferFetchES31, DrawNonFetchDrawFetchWithDifferentPrograms_Coherent)
    {
        ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
        setWhichExtension(COHERENT);
    
        GLProgram programNonFetch, programFetch1, programFetch2;
        programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
        programFetch1.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT_DIFFERENT1));
        programFetch2.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT_DIFFERENT2));
        ASSERT_GL_NO_ERROR();
    
        DrawNonFetchDrawFetchWithDifferentProgramsTest(programNonFetch, programFetch1, programFetch2);
    }
    
    // Testing non-coherent extension with the order of non-fetch program and fetch with different
    // programs
    TEST_P(FramebufferFetchES31, DrawNonFetchDrawFetchWithDifferentPrograms_NonCoherent)
    {
        ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
        setWhichExtension(NON_COHERENT);
    
        GLProgram programNonFetch, programFetch1, programFetch2;
        programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
        programFetch1.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT_DIFFERENT1));
        programFetch2.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT_DIFFERENT2));
        ASSERT_GL_NO_ERROR();
    
        DrawNonFetchDrawFetchWithDifferentProgramsTest(programNonFetch, programFetch1, programFetch2);
    }
    
    // Testing coherent extension with the order of draw fetch, blit and draw fetch
    TEST_P(FramebufferFetchES31, DrawFetchBlitDrawFetch_Coherent)
    {
        ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
        setWhichExtension(COHERENT);
    
        GLProgram programNonFetch, programFetch;
        programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
        programFetch.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT_DIFFERENT1));
        ASSERT_GL_NO_ERROR();
    
        DrawFetchBlitDrawFetchTest(programNonFetch, programFetch);
    }
    
    // Testing non-coherent extension with the order of draw fetch, blit and draw fetch
    TEST_P(FramebufferFetchES31, DrawFetchBlitDrawFetch_NonCoherent)
    {
        ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
        setWhichExtension(NON_COHERENT);
    
        GLProgram programNonFetch, programFetch;
        programNonFetch.makeRaster(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT));
        programFetch.makeRaster(k310VS, getFragmentShader(GLSL310_4ATTACHMENT_DIFFERENT1));
        ASSERT_GL_NO_ERROR();
    
        DrawFetchBlitDrawFetchTest(programNonFetch, programFetch);
    }
    
    // Testing coherent extension with program pipeline
    TEST_P(FramebufferFetchES31, ProgramPipeline_Coherent)
    {
        ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch"));
        setWhichExtension(COHERENT);
    
        ProgramPipelineTest(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT),
                            getFragmentShader(GLSL310_1ATTACHMENT));
    }
    
    // Testing non-coherent extension with program pipeline
    TEST_P(FramebufferFetchES31, ProgramPipeline_NonCoherent)
    {
        ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
        setWhichExtension(NON_COHERENT);
    
        ProgramPipelineTest(k310VS, getFragmentShader(GLSL310_NO_FETCH_1ATTACHMENT),
                            getFragmentShader(GLSL310_1ATTACHMENT));
    }
    
    // TODO: http://anglebug.com/5792
    TEST_P(FramebufferFetchES31, DISABLED_UniformUsageCombinations)
    {
        ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
    
        constexpr char kVS[] = R"(#version 310 es
    in highp vec4 a_position;
    out highp vec2 texCoord;
    
    void main()
    {
        gl_Position = a_position;
        texCoord = (a_position.xy * 0.5) + 0.5;
    })";
    
        constexpr char kFS[] = R"(#version 310 es
    #extension GL_EXT_shader_framebuffer_fetch_non_coherent : require
    
    layout(binding=0, offset=0) uniform atomic_uint atDiff;
    uniform sampler2D tex;
    
    layout(noncoherent, location = 0) inout highp vec4 o_color[4];
    in highp vec2 texCoord;
    
    void main()
    {
        highp vec4 texColor = texture(tex, texCoord);
    
        if (texColor != o_color[0])
        {
            atomicCounterIncrement(atDiff);
            o_color[0] = texColor;
        }
        else
        {
            if (atomicCounter(atDiff) > 0u)
            {
                atomicCounterDecrement(atDiff);
            }
        }
    
        if (texColor != o_color[1])
        {
            atomicCounterIncrement(atDiff);
            o_color[1] = texColor;
        }
        else
        {
            if (atomicCounter(atDiff) > 0u)
            {
                atomicCounterDecrement(atDiff);
            }
        }
    
        if (texColor != o_color[2])
        {
            atomicCounterIncrement(atDiff);
            o_color[2] = texColor;
        }
        else
        {
            if (atomicCounter(atDiff) > 0u)
            {
                atomicCounterDecrement(atDiff);
            }
        }
    
        if (texColor != o_color[3])
        {
            atomicCounterIncrement(atDiff);
            o_color[3] = texColor;
        }
        else
        {
            if (atomicCounter(atDiff) > 0u)
            {
                atomicCounterDecrement(atDiff);
            }
        }
    })";
    
        GLProgram program;
        program.makeRaster(kVS, kFS);
        glUseProgram(program);
    
        ASSERT_GL_NO_ERROR();
    
        GLFramebuffer framebuffer;
        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
        std::vector<GLColor> color0(kViewportWidth * kViewportHeight, GLColor::cyan);
        std::vector<GLColor> color1(kViewportWidth * kViewportHeight, GLColor::green);
        std::vector<GLColor> color2(kViewportWidth * kViewportHeight, GLColor::blue);
        std::vector<GLColor> color3(kViewportWidth * kViewportHeight, GLColor::black);
        GLTexture colorBufferTex[kMaxColorBuffer];
        GLenum colorAttachments[kMaxColorBuffer] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
                                                    GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3};
        glBindTexture(GL_TEXTURE_2D, colorBufferTex[0]);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                     GL_UNSIGNED_BYTE, color0.data());
        glBindTexture(GL_TEXTURE_2D, colorBufferTex[1]);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                     GL_UNSIGNED_BYTE, color1.data());
        glBindTexture(GL_TEXTURE_2D, colorBufferTex[2]);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                     GL_UNSIGNED_BYTE, color2.data());
        glBindTexture(GL_TEXTURE_2D, colorBufferTex[3]);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                     GL_UNSIGNED_BYTE, color3.data());
        glBindTexture(GL_TEXTURE_2D, 0);
        for (unsigned int i = 0; i < kMaxColorBuffer; i++)
        {
            glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachments[i], GL_TEXTURE_2D,
                                   colorBufferTex[i], 0);
        }
        glDrawBuffers(kMaxColorBuffer, &colorAttachments[0]);
    
        ASSERT_GL_NO_ERROR();
    
        GLBuffer atomicBuffer;
        glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicBuffer);
        glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_DYNAMIC_DRAW);
    
        // Reset atomic counter buffer
        GLuint *userCounters;
        userCounters = static_cast<GLuint *>(glMapBufferRange(
            GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint),
            GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT));
        memset(userCounters, 0, sizeof(GLuint));
        glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
    
        glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicBuffer);
        glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
    
        float color[4]      = {1.0f, 0.0f, 0.0f, 1.0f};
        GLint colorLocation = glGetUniformLocation(program, "u_color");
        glUniform4fv(colorLocation, 1, color);
    
        GLint positionLocation = glGetAttribLocation(program, "a_position");
        render(positionLocation, GL_TRUE);
    
        ASSERT_GL_NO_ERROR();
    
        for (unsigned int i = 0; i < kMaxColorBuffer; i++)
        {
            glReadBuffer(colorAttachments[i]);
            EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::black);
        }
    
        glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicBuffer);
        userCounters = static_cast<GLuint *>(
            glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), GL_MAP_READ_BIT));
        EXPECT_EQ(*userCounters, kViewportWidth * kViewportHeight * 2);
        glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
        glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
    
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }
    
    // Testing that binding the location value using GLES API is conflicted to the location value of the
    // fragment inout.
    TEST_P(FramebufferFetchES31, FixedUniformLocation)
    {
        ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_shader_framebuffer_fetch_non_coherent"));
    
        constexpr char kVS[] = R"(#version 310 es
    in highp vec4 a_position;
    
    void main (void)
    {
        gl_Position = a_position;
    })";
    
        constexpr char kFS[] = R"(#version 310 es
    #extension GL_EXT_shader_framebuffer_fetch_non_coherent : require
    layout(noncoherent, location = 0) inout highp vec4 o_color;
    
    layout(location = 0) uniform highp vec4 u_color;
    void main (void)
    {
        o_color += u_color;
    })";
    
        GLProgram program;
        program.makeRaster(kVS, kFS);
        glUseProgram(program);
    
        ASSERT_GL_NO_ERROR();
    
        GLFramebuffer framebuffer;
        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
        std::vector<GLColor> greenColor(kViewportWidth * kViewportHeight, GLColor::green);
        GLTexture colorBufferTex;
        glBindTexture(GL_TEXTURE_2D, colorBufferTex);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kViewportWidth, kViewportHeight, 0, GL_RGBA,
                     GL_UNSIGNED_BYTE, greenColor.data());
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBufferTex, 0);
    
        ASSERT_GL_NO_ERROR();
    
        float color[4]      = {1.0f, 0.0f, 0.0f, 1.0f};
        GLint colorLocation = glGetUniformLocation(program, "u_color");
        glUniform4fv(colorLocation, 1, color);
    
        GLint positionLocation = glGetAttribLocation(program, "a_position");
        render(positionLocation, GL_TRUE);
    
        ASSERT_GL_NO_ERROR();
    
        EXPECT_PIXEL_COLOR_EQ(kViewportWidth / 2, kViewportHeight / 2, GLColor::yellow);
    
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }
    
    GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FramebufferFetchES31);
    ANGLE_INSTANTIATE_TEST_ES31_AND(FramebufferFetchES31, WithDirectSPIRVGeneration(ES31_VULKAN()));
    }  // namespace angle