//
// Copyright 2024 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.
//

#include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"

using namespace angle;

constexpr int kPixelColorThreshhold = 8;

class AdvancedBlendTest : public ANGLETest<>
{
  protected:
    AdvancedBlendTest()
    {
        setWindowWidth(128);
        setWindowHeight(128);
        setConfigRedBits(8);
        setConfigGreenBits(8);
        setConfigBlueBits(8);
        setConfigAlphaBits(8);
        setExtensionsEnabled(false);
    }

    void callBlendBarrier(APIExtensionVersion usedExtension);
    void testAdvancedBlendNotAppliedWhenBlendIsDisabled(APIExtensionVersion usedExtension);
    void testAdvancedBlendDisabledAndThenEnabled(APIExtensionVersion usedExtension);
    void testAdvancedBlendEnabledAndThenDisabled(APIExtensionVersion usedExtension);
};

class AdvancedBlendTestES32 : public AdvancedBlendTest
{};

// Test that advanced blend cannot be used when a non-zero draw buffer is enabled.
TEST_P(AdvancedBlendTest, NonZeroDrawBufferDisallowed)
{
    ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_KHR_blend_equation_advanced"));

    GLFramebuffer fbo;
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);

    std::array<GLRenderbuffer, 4> rbo;
    for (uint32_t i = 0; i < 4; ++i)
    {
        glBindRenderbuffer(GL_RENDERBUFFER, rbo[i]);
        glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_RENDERBUFFER,
                                  rbo[i]);
    }
    EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
    ASSERT_GL_NO_ERROR();

    GLenum enabled[4] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2,
                         GL_COLOR_ATTACHMENT3};
    glDrawBuffers(4, enabled);

    constexpr char kVS[] = R"(#version 300 es
precision highp float;
void main()
{
    switch (gl_VertexID)
    {
        case 0:  gl_Position = vec4(-1, -1, 0, 1); break;
        case 1:  gl_Position = vec4( 3, -1, 0, 1); break;
        default: gl_Position = vec4(-1, 3, 0, 1); break;
    }
})";

    constexpr char kFS[] = R"(#version 300 es
#extension GL_KHR_blend_equation_advanced : require
layout (blend_support_multiply) out;
precision mediump float;
out vec4 fragColor;
void main()
{
    fragColor = vec4(1., 0., 0., 1.);
})";
    ANGLE_GL_PROGRAM(program, kVS, kFS);
    glUseProgram(program);

    glEnable(GL_BLEND);
    glBlendEquation(GL_MULTIPLY_KHR);

    // Invalid draw because all 4 draw buffers are enabled.
    ASSERT_GL_NO_ERROR();
    glDrawArrays(GL_TRIANGLES, 0, 3);
    EXPECT_GL_ERROR(GL_INVALID_OPERATION);

    enabled[1] = GL_NONE;
    enabled[2] = GL_NONE;
    glDrawBuffers(4, enabled);

    // Still invalid because draw buffer #3 is enabled.
    ASSERT_GL_NO_ERROR();
    glDrawArrays(GL_TRIANGLES, 0, 3);
    EXPECT_GL_ERROR(GL_INVALID_OPERATION);

    enabled[0] = GL_NONE;
    enabled[1] = GL_COLOR_ATTACHMENT1;
    enabled[3] = GL_NONE;
    glDrawBuffers(4, enabled);

    // Even though a single draw buffer is enabled, it's not index 0 so it's still invalid
    ASSERT_GL_NO_ERROR();
    glDrawArrays(GL_TRIANGLES, 0, 3);
    EXPECT_GL_ERROR(GL_INVALID_OPERATION);

    enabled[0] = GL_COLOR_ATTACHMENT0;
    enabled[1] = GL_NONE;
    glDrawBuffers(4, enabled);

    // When only color attachment 0 is enabled, the draw is valid.
    glClearColor(1, 1, 1, 1);
    glClear(GL_COLOR_BUFFER_BIT);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    ASSERT_GL_NO_ERROR();
    EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);

    // It's also ok to render to multiple attachments if blend is not enabled on the attachment that
    // has advanced blend..
    if (EnsureGLExtensionEnabled("GL_OES_draw_buffers_indexed"))
    {
        // Enable two attachments
        enabled[1] = GL_COLOR_ATTACHMENT1;
        glDrawBuffers(4, enabled);

        // Enable blend only on attachment 0
        glDisable(GL_BLEND);
        glEnableiOES(GL_BLEND, 0);
        glDisableiOES(GL_BLEND, 1);

        // Set advanced blend on the attachment that has blend disabled.  Set a non-advanced blend
        // on the one that has blend enabled.
        glBlendEquationiOES(0, GL_FUNC_ADD);
        glBlendFunciOES(0, GL_ONE, GL_ONE);
        glBlendEquationiOES(1, GL_MULTIPLY_KHR);

        glClearColor(0, 1, 0, 1);
        glClear(GL_COLOR_BUFFER_BIT);
        glDrawArrays(GL_TRIANGLES, 0, 3);
        ASSERT_GL_NO_ERROR();
        EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);

        // If advanced blend is enabled on a NONE attachment, that's also ok.
        enabled[1] = GL_NONE;
        glDrawBuffers(4, enabled);
        glEnableiOES(GL_BLEND, 1);

        glClearColor(0, 0, 1, 1);
        glClear(GL_COLOR_BUFFER_BIT);
        glDrawArrays(GL_TRIANGLES, 0, 3);
        ASSERT_GL_NO_ERROR();
        EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
    }
}

void AdvancedBlendTest::callBlendBarrier(APIExtensionVersion usedExtension)
{
    ASSERT(usedExtension == APIExtensionVersion::Core || usedExtension == APIExtensionVersion::KHR);
    if (usedExtension == APIExtensionVersion::KHR)
    {
        glBlendBarrierKHR();
    }
    else
    {
        glBlendBarrier();
    }
}

void AdvancedBlendTest::testAdvancedBlendNotAppliedWhenBlendIsDisabled(
    APIExtensionVersion usedExtension)
{
    ASSERT(usedExtension == APIExtensionVersion::Core || usedExtension == APIExtensionVersion::KHR);

    constexpr char kGLSLVersion30[] = R"(#version 300 es
)";
    constexpr char kGLSLVersion32[] = R"(#version 320 es
)";
    constexpr char kBlendKHR[]      = R"(#extension GL_KHR_blend_equation_advanced : require
)";

    std::string vertSrc;
    std::string fragSrc;

    if (usedExtension == APIExtensionVersion::KHR)
    {
        vertSrc.append(kGLSLVersion30);
        fragSrc.append(kGLSLVersion30);
        fragSrc.append(kBlendKHR);
    }
    else
    {
        vertSrc.append(kGLSLVersion32);
        fragSrc.append(kGLSLVersion32);
    }

    constexpr char kVertSrcBody[] = R"(
        in highp vec4 a_position;
        in mediump vec4 a_color;
        out mediump vec4 v_color;
        void main()
        {
            gl_Position = a_position;
            v_color = a_color;
        }
    )";
    vertSrc.append(kVertSrcBody);

    constexpr char kFragSrcBody[] = R"(
        in mediump vec4 v_color;
        layout(blend_support_colorburn) out;
        layout(location = 0) out mediump vec4 o_color;
        void main()
        {
            o_color = v_color;
        }
    )";
    fragSrc.append(kFragSrcBody);

    ANGLE_GL_PROGRAM(program, vertSrc.c_str(), fragSrc.c_str());
    glUseProgram(program);

    std::array<GLfloat, 16> attribPosData = {1, 1,  0.5, 1, -1, 1,  0.5, 1,
                                             1, -1, 0.5, 1, -1, -1, 0.5, 1};

    GLint attribPosLoc = glGetAttribLocation(1, "a_position");
    ASSERT(attribPosLoc >= 0);
    glEnableVertexAttribArray(attribPosLoc);
    glVertexAttribPointer(attribPosLoc, 4, GL_FLOAT, GL_FALSE, 0, attribPosData.data());

    std::array<GLfloat, 16> attribColorData1 = {1, 0.2, 0.5, 1, 1, 0.2, 0.5, 1,
                                                1, 0.2, 0.5, 1, 1, 0.2, 0.5, 1};
    GLint attribColorLoc                     = glGetAttribLocation(1, "a_color");
    ASSERT(attribColorLoc >= 0);
    glEnableVertexAttribArray(attribColorLoc);
    glVertexAttribPointer(attribColorLoc, 4, GL_FLOAT, GL_FALSE, 0, attribColorData1.data());

    glBlendEquation(GL_COLORBURN);

    const uint16_t indices[] = {0, 1, 2, 2, 1, 3};
    glClearColor(0.5, 0.5, 0.5, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    // Disable the blend. The next glDrawElements() should not blend the a_color with clear color
    const int w = getWindowWidth();
    const int h = getWindowHeight();
    glDisable(GL_BLEND);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[0]);
    EXPECT_PIXEL_COLOR_NEAR(w / 2, h / 2, GLColor(255, 51, 128, 255), kPixelColorThreshhold);
}

// Test that when blending is disabled, advanced blend is not applied.
// Regression test for a bug in the emulation path in the Vulkan backend.
TEST_P(AdvancedBlendTest, AdvancedBlendNotAppliedWhenBlendIsDisabledKHR)
{
    ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_KHR_blend_equation_advanced"));
    testAdvancedBlendNotAppliedWhenBlendIsDisabled(APIExtensionVersion::KHR);
}

// Test that when blending is disabled, advanced blend is not applied (using ES 3.2).
TEST_P(AdvancedBlendTestES32, AdvancedBlendNotAppliedWhenBlendIsDisabled)
{
    testAdvancedBlendNotAppliedWhenBlendIsDisabled(APIExtensionVersion::Core);
}

void AdvancedBlendTest::testAdvancedBlendDisabledAndThenEnabled(APIExtensionVersion usedExtension)
{
    ASSERT(usedExtension == APIExtensionVersion::Core || usedExtension == APIExtensionVersion::KHR);

    constexpr char kGLSLVersion30[] = R"(#version 300 es
)";
    constexpr char kGLSLVersion32[] = R"(#version 320 es
)";
    constexpr char kBlendKHR[]      = R"(#extension GL_KHR_blend_equation_advanced : require
)";

    std::string vertSrc;
    std::string fragSrc;

    if (usedExtension == APIExtensionVersion::KHR)
    {
        vertSrc.append(kGLSLVersion30);
        fragSrc.append(kGLSLVersion30);
        fragSrc.append(kBlendKHR);
    }
    else
    {
        vertSrc.append(kGLSLVersion32);
        fragSrc.append(kGLSLVersion32);
    }

    constexpr char kVertSrcBody[] = R"(
        in highp vec4 a_position;
        in mediump vec4 a_color;
        out mediump vec4 v_color;
        void main()
        {
            gl_Position = a_position;
            v_color = a_color;
        }
    )";
    vertSrc.append(kVertSrcBody);

    constexpr char kFragSrcBody[] = R"(
        in mediump vec4 v_color;
        layout(blend_support_colorburn, blend_support_multiply) out;
        layout(location = 0) out mediump vec4 o_color;
        void main()
        {
            o_color = v_color;
        }
    )";
    fragSrc.append(kFragSrcBody);

    ANGLE_GL_PROGRAM(program, vertSrc.c_str(), fragSrc.c_str());
    glUseProgram(program);

    std::array<GLfloat, 16> attribPosData = {1, 1,  0.5, 1, -1, 1,  0.5, 1,
                                             1, -1, 0.5, 1, -1, -1, 0.5, 1};

    GLint attribPosLoc = glGetAttribLocation(1, "a_position");
    ASSERT(attribPosLoc >= 0);
    glEnableVertexAttribArray(attribPosLoc);
    glVertexAttribPointer(attribPosLoc, 4, GL_FLOAT, GL_FALSE, 0, attribPosData.data());

    std::array<GLfloat, 16> attribColorData1 = {1, 0.2, 0.5, 1, 1, 0.2, 0.5, 1,
                                                1, 0.2, 0.5, 1, 1, 0.2, 0.5, 1};
    GLint attribColorLoc                     = glGetAttribLocation(1, "a_color");
    ASSERT(attribColorLoc >= 0);
    glEnableVertexAttribArray(attribColorLoc);
    glVertexAttribPointer(attribColorLoc, 4, GL_FLOAT, GL_FALSE, 0, attribColorData1.data());

    glBlendEquation(GL_COLORBURN);

    const uint16_t indices[] = {0, 1, 2, 2, 1, 3};
    glClearColor(0.5, 0.5, 0.5, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    // Disable the blend. The next glDrawElements() should not blend the a_color with clear color
    glDisable(GL_BLEND);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[0]);

    const int w = getWindowWidth();
    const int h = getWindowHeight();
    glEnable(GL_SCISSOR_TEST);
    glScissor(0, 0, w / 2, h);
    // Enable the blend. The next glDrawElements() should blend a_color
    // with the the existing framebuffer output with GL_COLORBURN blend mode
    glEnable(GL_BLEND);
    // Test the blend with coherent blend disabled. This make the test cover both devices that
    // support / do not support GL_KHR_blend_equation_advanced_coherent
    if (EnsureGLExtensionEnabled("GL_KHR_blend_equation_advanced_coherent"))
    {
        glDisable(GL_BLEND_ADVANCED_COHERENT_KHR);
    }
    callBlendBarrier(usedExtension);
    std::array<GLfloat, 16> attribColorData2 = {0.5, 0.5, 0, 1, 0.5, 0.5, 0, 1,
                                                0.5, 0.5, 0, 1, 0.5, 0.5, 0, 1};
    glEnableVertexAttribArray(attribColorLoc);
    glVertexAttribPointer(attribColorLoc, 4, GL_FLOAT, GL_FALSE, 0, attribColorData2.data());
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[0]);

    EXPECT_PIXEL_COLOR_NEAR(w / 4, h / 2, GLColor(255, 0, 0, 255), kPixelColorThreshhold);
    EXPECT_PIXEL_COLOR_NEAR(3 * w / 4, h / 2, GLColor(255, 51, 128, 255), kPixelColorThreshhold);
}

// Test that when blending is disabled, advanced blend is not applied, but is applied after
// it is enabled.
// Regression test for a bug in the emulation path in the Vulkan backend.
TEST_P(AdvancedBlendTest, AdvancedBlendDisabledAndThenEnabledKHR)
{
    ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_KHR_blend_equation_advanced"));
    testAdvancedBlendDisabledAndThenEnabled(APIExtensionVersion::KHR);
}

// Test that when blending is disabled, advanced blend is not applied, but is applied after
// it is enabled (using ES 3.2).
TEST_P(AdvancedBlendTestES32, AdvancedBlendDisabledAndThenEnabled)
{
    testAdvancedBlendDisabledAndThenEnabled(APIExtensionVersion::Core);
}

void AdvancedBlendTest::testAdvancedBlendEnabledAndThenDisabled(APIExtensionVersion usedExtension)
{
    ASSERT(usedExtension == APIExtensionVersion::Core || usedExtension == APIExtensionVersion::KHR);

    constexpr char kGLSLVersion30[] = R"(#version 300 es
)";
    constexpr char kGLSLVersion32[] = R"(#version 320 es
)";
    constexpr char kBlendKHR[]      = R"(#extension GL_KHR_blend_equation_advanced : require
)";

    std::string vertSrc;
    std::string fragSrc;

    if (usedExtension == APIExtensionVersion::KHR)
    {
        vertSrc.append(kGLSLVersion30);
        fragSrc.append(kGLSLVersion30);
        fragSrc.append(kBlendKHR);
    }
    else
    {
        vertSrc.append(kGLSLVersion32);
        fragSrc.append(kGLSLVersion32);
    }

    constexpr char kVertSrcBody[] = R"(
        in highp vec4 a_position;
        in mediump vec4 a_color;
        out mediump vec4 v_color;
        void main()
        {
            gl_Position = a_position;
            v_color = a_color;
        }
    )";
    vertSrc.append(kVertSrcBody);

    constexpr char kFragSrcBody[] = R"(
        in mediump vec4 v_color;
        layout(blend_support_colorburn, blend_support_darken) out;
        layout(location = 0) out mediump vec4 o_color;
        void main()
        {
            o_color = v_color;
        }
    )";
    fragSrc.append(kFragSrcBody);

    ANGLE_GL_PROGRAM(program, vertSrc.c_str(), fragSrc.c_str());
    glUseProgram(program);

    std::array<GLfloat, 16> attribPosData = {1, 1,  0.5, 1, -1, 1,  0.5, 1,
                                             1, -1, 0.5, 1, -1, -1, 0.5, 1};

    GLint attribPosLoc = glGetAttribLocation(1, "a_position");
    ASSERT(attribPosLoc >= 0);
    glEnableVertexAttribArray(attribPosLoc);
    glVertexAttribPointer(attribPosLoc, 4, GL_FLOAT, GL_FALSE, 0, attribPosData.data());

    std::array<GLfloat, 16> attribColorData1 = {1, 0.2, 0.5, 1, 1, 0.2, 0.5, 1,
                                                1, 0.2, 0.5, 1, 1, 0.2, 0.5, 1};
    GLint attribColorLoc                     = glGetAttribLocation(1, "a_color");
    ASSERT(attribColorLoc >= 0);
    glEnableVertexAttribArray(attribColorLoc);
    glVertexAttribPointer(attribColorLoc, 4, GL_FLOAT, GL_FALSE, 0, attribColorData1.data());

    glBlendEquation(GL_DARKEN);

    const uint16_t indices[] = {0, 1, 2, 2, 1, 3};
    glClearColor(0.5, 0.5, 0.5, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    // Enable the blend. The next glDrawElements() should blend the a_color with clear color
    // using the GL_DARKEN blend mode
    glEnable(GL_BLEND);
    // Test the blend with coherent blend disabled. This make the test cover both devices that
    // support / do not support GL_KHR_blend_equation_advanced_coherent
    if (EnsureGLExtensionEnabled("GL_KHR_blend_equation_advanced_coherent"))
    {
        glDisable(GL_BLEND_ADVANCED_COHERENT_KHR);
    }
    callBlendBarrier(usedExtension);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[0]);

    // Disable the blend. The next glDrawElements() should not blend the a_color with
    // the existing framebuffer output with GL_DARKEN blend mode
    const int w = getWindowWidth();
    const int h = getWindowHeight();
    glEnable(GL_SCISSOR_TEST);
    glScissor(0, 0, w / 2, h);
    glDisable(GL_BLEND);
    std::array<GLfloat, 16> attribColorData2 = {0.5, 0.5, 0, 1, 0.5, 0.5, 0, 1,
                                                0.5, 0.5, 0, 1, 0.5, 0.5, 0, 1};
    glEnableVertexAttribArray(attribColorLoc);
    glVertexAttribPointer(attribColorLoc, 4, GL_FLOAT, GL_FALSE, 0, attribColorData2.data());
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, &indices[0]);

    EXPECT_PIXEL_COLOR_NEAR(w / 4, h / 2, GLColor(128, 128, 0, 255), kPixelColorThreshhold);
    EXPECT_PIXEL_COLOR_NEAR(3 * w / 4, h / 2, GLColor(128, 51, 128, 255), kPixelColorThreshhold);
}

// Test that when blending is enabled, advanced blend is applied, but is not applied after
// it is disabled.
// Regression test for a bug in the emulation path in the Vulkan backend.
TEST_P(AdvancedBlendTest, AdvancedBlendEnabledAndThenDisabledKHR)
{
    ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_KHR_blend_equation_advanced"));
    testAdvancedBlendEnabledAndThenDisabled(APIExtensionVersion::KHR);
}

// Test that extension blend barrier results in an error if the extension is not enabled.
TEST_P(AdvancedBlendTest, AdvancedBlendBarrierKHRFailsIfNotSupported)
{
    ASSERT_FALSE(IsGLExtensionEnabled("GL_KHR_blend_equation_advanced"));

    glBlendBarrierKHR();
    EXPECT_GL_ERROR(GL_INVALID_OPERATION);
}

// Test that when blending is enabled, advanced blend is applied, but is not applied after
// it is disabled (using ES 3.2).
TEST_P(AdvancedBlendTestES32, AdvancedBlendEnabledAndThenDisabled)
{
    testAdvancedBlendEnabledAndThenDisabled(APIExtensionVersion::Core);
}

// Test that core blend barrier results in no error if the extension is not enabled.
TEST_P(AdvancedBlendTestES32, AdvancedBlendBarrierAlwaysPasses)
{
    ASSERT_FALSE(IsGLExtensionEnabled("GL_KHR_blend_equation_advanced"));

    glBlendBarrier();
    EXPECT_GL_NO_ERROR();
}

// Test querying advanced blend equation coherent on supported devices (enabled by default).
TEST_P(AdvancedBlendTest, AdvancedBlendCoherentQuery)
{
    ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_KHR_blend_equation_advanced_coherent"));

    GLint status = -1;
    glGetIntegerv(GL_BLEND_ADVANCED_COHERENT_KHR, &status);
    EXPECT_GL_NO_ERROR();
    EXPECT_EQ(status, 1);

    glDisable(GL_BLEND_ADVANCED_COHERENT_KHR);
    glGetIntegerv(GL_BLEND_ADVANCED_COHERENT_KHR, &status);
    EXPECT_GL_NO_ERROR();
    EXPECT_EQ(status, 0);

    glEnable(GL_BLEND_ADVANCED_COHERENT_KHR);
    glGetIntegerv(GL_BLEND_ADVANCED_COHERENT_KHR, &status);
    EXPECT_GL_NO_ERROR();
    EXPECT_EQ(status, 1);

    const GLboolean statusBool = glIsEnabled(GL_BLEND_ADVANCED_COHERENT_KHR);
    EXPECT_GL_NO_ERROR();
    EXPECT_TRUE(statusBool);
}

// Test that querying advanced blend equation coherent results in an error as if this enum does not
// exist.
TEST_P(AdvancedBlendTest, AdvancedBlendCoherentQueryFailsIfNotSupported)
{
    ASSERT_FALSE(IsGLExtensionEnabled("GL_KHR_blend_equation_advanced_coherent"));

    GLint status = -1;
    glGetIntegerv(GL_BLEND_ADVANCED_COHERENT_KHR, &status);
    EXPECT_GL_ERROR(GL_INVALID_ENUM);

    glEnable(GL_BLEND_ADVANCED_COHERENT_KHR);
    EXPECT_GL_ERROR(GL_INVALID_ENUM);
}

GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AdvancedBlendTest);
ANGLE_INSTANTIATE_TEST_ES3(AdvancedBlendTest);

GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AdvancedBlendTestES32);
ANGLE_INSTANTIATE_TEST_ES32(AdvancedBlendTestES32);
