Path: blob/main_old/src/tests/gl_tests/BlendFuncExtendedTest.cpp
1693 views
//1// Copyright 2018 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//5// BlendFuncExtendedTest6// Test EXT_blend_func_extended78#include "test_utils/ANGLETest.h"9#include "test_utils/gl_raii.h"1011#include "util/shader_utils.h"1213#include <algorithm>14#include <cmath>15#include <fstream>1617using namespace angle;1819namespace20{2122// Partial implementation of weight function for GLES 2 blend equation that23// is dual-source aware.24template <int factor, int index>25float Weight(const float /*dst*/[4], const float src[4], const float src1[4])26{27if (factor == GL_SRC_COLOR)28return src[index];29if (factor == GL_SRC_ALPHA)30return src[3];31if (factor == GL_SRC1_COLOR_EXT)32return src1[index];33if (factor == GL_SRC1_ALPHA_EXT)34return src1[3];35if (factor == GL_ONE_MINUS_SRC1_COLOR_EXT)36return 1.0f - src1[index];37if (factor == GL_ONE_MINUS_SRC1_ALPHA_EXT)38return 1.0f - src1[3];39return 0.0f;40}4142GLubyte ScaleChannel(float weight)43{44return static_cast<GLubyte>(std::floor(std::max(0.0f, std::min(1.0f, weight)) * 255.0f));45}4647// Implementation of GLES 2 blend equation that is dual-source aware.48template <int RGBs, int RGBd, int As, int Ad>49void BlendEquationFuncAdd(const float dst[4],50const float src[4],51const float src1[4],52angle::GLColor *result)53{54float r[4];55r[0] = src[0] * Weight<RGBs, 0>(dst, src, src1) + dst[0] * Weight<RGBd, 0>(dst, src, src1);56r[1] = src[1] * Weight<RGBs, 1>(dst, src, src1) + dst[1] * Weight<RGBd, 1>(dst, src, src1);57r[2] = src[2] * Weight<RGBs, 2>(dst, src, src1) + dst[2] * Weight<RGBd, 2>(dst, src, src1);58r[3] = src[3] * Weight<As, 3>(dst, src, src1) + dst[3] * Weight<Ad, 3>(dst, src, src1);5960result->R = ScaleChannel(r[0]);61result->G = ScaleChannel(r[1]);62result->B = ScaleChannel(r[2]);63result->A = ScaleChannel(r[3]);64}6566void CheckPixels(GLint x,67GLint y,68GLsizei width,69GLsizei height,70GLint tolerance,71const angle::GLColor &color)72{73for (GLint yy = 0; yy < height; ++yy)74{75for (GLint xx = 0; xx < width; ++xx)76{77const auto px = x + xx;78const auto py = y + yy;79EXPECT_PIXEL_COLOR_NEAR(px, py, color, 1);80}81}82}8384const GLuint kWidth = 100;85const GLuint kHeight = 100;8687class EXTBlendFuncExtendedTest : public ANGLETest88{};8990class EXTBlendFuncExtendedTestES3 : public ANGLETest91{};9293class EXTBlendFuncExtendedDrawTest : public ANGLETest94{95protected:96EXTBlendFuncExtendedDrawTest() : mProgram(0)97{98setWindowWidth(kWidth);99setWindowHeight(kHeight);100setConfigRedBits(8);101setConfigGreenBits(8);102setConfigBlueBits(8);103setConfigAlphaBits(8);104}105106void testSetUp() override107{108glGenBuffers(1, &mVBO);109glBindBuffer(GL_ARRAY_BUFFER, mVBO);110111static const float vertices[] = {1121.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f,113};114glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);115116ASSERT_GL_NO_ERROR();117}118119void testTearDown() override120{121glDeleteBuffers(1, &mVBO);122if (mProgram)123{124glDeleteProgram(mProgram);125}126127ASSERT_GL_NO_ERROR();128}129130void makeProgram(const char *vertSource, const char *fragSource)131{132mProgram = CompileProgram(vertSource, fragSource);133134ASSERT_NE(0u, mProgram);135}136137virtual GLint getVertexAttribLocation(const char *name)138{139return glGetAttribLocation(mProgram, name);140}141142virtual GLint getFragmentUniformLocation(const char *name)143{144return glGetUniformLocation(mProgram, name);145}146147virtual void setUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)148{149glUniform4f(location, v0, v1, v2, v3);150}151152void drawTest()153{154glUseProgram(mProgram);155156GLint position = getVertexAttribLocation(essl1_shaders::PositionAttrib());157GLint src0 = getFragmentUniformLocation("src0");158GLint src1 = getFragmentUniformLocation("src1");159ASSERT_GL_NO_ERROR();160161glBindBuffer(GL_ARRAY_BUFFER, mVBO);162glEnableVertexAttribArray(position);163glVertexAttribPointer(position, 2, GL_FLOAT, GL_FALSE, 0, 0);164ASSERT_GL_NO_ERROR();165166static const float kDst[4] = {0.5f, 0.5f, 0.5f, 0.5f};167static const float kSrc0[4] = {1.0f, 1.0f, 1.0f, 1.0f};168static const float kSrc1[4] = {0.3f, 0.6f, 0.9f, 0.7f};169170setUniform4f(src0, kSrc0[0], kSrc0[1], kSrc0[2], kSrc0[3]);171setUniform4f(src1, kSrc1[0], kSrc1[1], kSrc1[2], kSrc1[3]);172ASSERT_GL_NO_ERROR();173174glEnable(GL_BLEND);175glBlendEquation(GL_FUNC_ADD);176glViewport(0, 0, kWidth, kHeight);177glClearColor(kDst[0], kDst[1], kDst[2], kDst[3]);178ASSERT_GL_NO_ERROR();179180{181glBlendFuncSeparate(GL_SRC1_COLOR_EXT, GL_SRC_ALPHA, GL_ONE_MINUS_SRC1_COLOR_EXT,182GL_ONE_MINUS_SRC1_ALPHA_EXT);183184glClear(GL_COLOR_BUFFER_BIT);185glDrawArrays(GL_TRIANGLES, 0, 6);186ASSERT_GL_NO_ERROR();187188// verify189angle::GLColor color;190BlendEquationFuncAdd<GL_SRC1_COLOR_EXT, GL_SRC_ALPHA, GL_ONE_MINUS_SRC1_COLOR_EXT,191GL_ONE_MINUS_SRC1_ALPHA_EXT>(kDst, kSrc0, kSrc1, &color);192193CheckPixels(kWidth / 4, (3 * kHeight) / 4, 1, 1, 1, color);194CheckPixels(kWidth - 1, 0, 1, 1, 1, color);195}196197{198glBlendFuncSeparate(GL_ONE_MINUS_SRC1_COLOR_EXT, GL_ONE_MINUS_SRC_ALPHA,199GL_ONE_MINUS_SRC_COLOR, GL_SRC1_ALPHA_EXT);200201glClear(GL_COLOR_BUFFER_BIT);202glDrawArrays(GL_TRIANGLES, 0, 6);203ASSERT_GL_NO_ERROR();204205// verify206angle::GLColor color;207BlendEquationFuncAdd<GL_ONE_MINUS_SRC1_COLOR_EXT, GL_ONE_MINUS_SRC_ALPHA,208GL_ONE_MINUS_SRC_COLOR, GL_SRC1_ALPHA_EXT>(kDst, kSrc0, kSrc1,209&color);210211CheckPixels(kWidth / 4, (3 * kHeight) / 4, 1, 1, 1, color);212CheckPixels(kWidth - 1, 0, 1, 1, 1, color);213}214}215216GLuint mVBO;217GLuint mProgram;218};219220class EXTBlendFuncExtendedDrawTestES3 : public EXTBlendFuncExtendedDrawTest221{222protected:223EXTBlendFuncExtendedDrawTestES3() : EXTBlendFuncExtendedDrawTest(), mIsES31OrNewer(false) {}224225void testSetUp() override226{227EXTBlendFuncExtendedDrawTest::testSetUp();228if (getClientMajorVersion() > 3 ||229(getClientMajorVersion() == 3 && getClientMinorVersion() >= 1))230{231mIsES31OrNewer = true;232}233}234235virtual void checkOutputIndexQuery(const char *name, GLint expectedIndex)236{237GLint index = glGetFragDataIndexEXT(mProgram, name);238EXPECT_EQ(expectedIndex, index);239if (mIsES31OrNewer)240{241index = glGetProgramResourceLocationIndexEXT(mProgram, GL_PROGRAM_OUTPUT, name);242EXPECT_EQ(expectedIndex, index);243}244else245{246glGetProgramResourceLocationIndexEXT(mProgram, GL_PROGRAM_OUTPUT, name);247EXPECT_GL_ERROR(GL_INVALID_OPERATION);248}249}250251void LinkProgram()252{253glLinkProgram(mProgram);254GLint linked = 0;255glGetProgramiv(mProgram, GL_LINK_STATUS, &linked);256EXPECT_NE(0, linked);257glUseProgram(mProgram);258return;259}260261private:262bool mIsES31OrNewer;263};264265class EXTBlendFuncExtendedDrawTestES31 : public EXTBlendFuncExtendedDrawTestES3266{267protected:268EXTBlendFuncExtendedDrawTestES31()269: EXTBlendFuncExtendedDrawTestES3(), mPipeline(0), mVertexProgram(0), mFragProgram(0)270{}271272GLint getVertexAttribLocation(const char *name) override273{274return glGetAttribLocation(mVertexProgram, name);275}276277GLint getFragmentUniformLocation(const char *name) override278{279return glGetUniformLocation(mFragProgram, name);280}281282void setUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) override283{284glActiveShaderProgram(mPipeline, mFragProgram);285EXTBlendFuncExtendedDrawTest::setUniform4f(location, v0, v1, v2, v3);286}287288void checkOutputIndexQuery(const char *name, GLint expectedIndex) override289{290GLint index = glGetFragDataIndexEXT(mFragProgram, name);291EXPECT_EQ(expectedIndex, index);292index = glGetProgramResourceLocationIndexEXT(mFragProgram, GL_PROGRAM_OUTPUT, name);293EXPECT_EQ(expectedIndex, index);294}295296void setupProgramPipeline(const char *vertexSource, const char *fragmentSource)297{298mVertexProgram = createShaderProgram(GL_VERTEX_SHADER, vertexSource);299ASSERT_NE(mVertexProgram, 0u);300mFragProgram = createShaderProgram(GL_FRAGMENT_SHADER, fragmentSource);301ASSERT_NE(mFragProgram, 0u);302303// Generate a program pipeline and attach the programs to their respective stages304glGenProgramPipelines(1, &mPipeline);305EXPECT_GL_NO_ERROR();306glUseProgramStages(mPipeline, GL_VERTEX_SHADER_BIT, mVertexProgram);307EXPECT_GL_NO_ERROR();308glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProgram);309EXPECT_GL_NO_ERROR();310glBindProgramPipeline(mPipeline);311EXPECT_GL_NO_ERROR();312}313314GLuint createShaderProgram(GLenum type, const GLchar *shaderString)315{316GLShader shader(type);317if (!shader.get())318{319return 0;320}321322glShaderSource(shader, 1, &shaderString, nullptr);323glCompileShader(shader);324325GLuint program = glCreateProgram();326327if (program)328{329GLint compiled;330glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);331glProgramParameteri(program, GL_PROGRAM_SEPARABLE, GL_TRUE);332if (compiled)333{334glAttachShader(program, shader);335glLinkProgram(program);336glDetachShader(program, shader);337}338}339340EXPECT_GL_NO_ERROR();341342return program;343}344345void testTearDown() override346{347EXTBlendFuncExtendedDrawTest::testTearDown();348if (mVertexProgram)349{350glDeleteProgram(mVertexProgram);351}352if (mFragProgram)353{354glDeleteProgram(mFragProgram);355}356if (mPipeline)357{358glDeleteProgramPipelines(1, &mPipeline);359}360361ASSERT_GL_NO_ERROR();362}363364GLuint mPipeline;365GLuint mVertexProgram;366GLuint mFragProgram;367};368} // namespace369370// Test EXT_blend_func_extended related gets.371TEST_P(EXTBlendFuncExtendedTest, TestMaxDualSourceDrawBuffers)372{373ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));374375GLint maxDualSourceDrawBuffers = 0;376glGetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT, &maxDualSourceDrawBuffers);377EXPECT_GT(maxDualSourceDrawBuffers, 0);378379ASSERT_GL_NO_ERROR();380}381382// Test a shader with EXT_blend_func_extended and gl_SecondaryFragColorEXT.383// Outputs to primary color buffer using primary and secondary colors.384TEST_P(EXTBlendFuncExtendedDrawTest, FragColor)385{386ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));387388const char *kFragColorShader =389"#extension GL_EXT_blend_func_extended : require\n"390"precision mediump float;\n"391"uniform vec4 src0;\n"392"uniform vec4 src1;\n"393"void main() {\n"394" gl_FragColor = src0;\n"395" gl_SecondaryFragColorEXT = src1;\n"396"}\n";397398makeProgram(essl1_shaders::vs::Simple(), kFragColorShader);399400drawTest();401}402403// Test a shader with EXT_blend_func_extended and gl_FragData.404// Outputs to a color buffer using primary and secondary frag data.405TEST_P(EXTBlendFuncExtendedDrawTest, FragData)406{407ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));408409// Suspected VK driver bug http://anglebug.com/5523410ANGLE_SKIP_TEST_IF(IsVulkan() && (IsNVIDIA() || IsPixel2()));411412// Suspected AMD VK driver bug http://anglebug.com/5537413ANGLE_SKIP_TEST_IF(IsVulkan() && IsWindows() && IsAMD());414415const char *kFragColorShader =416"#extension GL_EXT_blend_func_extended : require\n"417"precision mediump float;\n"418"uniform vec4 src0;\n"419"uniform vec4 src1;\n"420"void main() {\n"421" gl_FragData[0] = src0;\n"422" gl_SecondaryFragDataEXT[0] = src1;\n"423"}\n";424425makeProgram(essl1_shaders::vs::Simple(), kFragColorShader);426427drawTest();428}429430// Test an ESSL 3.00 shader that uses two fragment outputs with locations specified in the shader.431TEST_P(EXTBlendFuncExtendedDrawTestES3, FragmentOutputLocationsInShader)432{433ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));434435const char *kFragColorShader = R"(#version 300 es436#extension GL_EXT_blend_func_extended : require437precision mediump float;438uniform vec4 src0;439uniform vec4 src1;440layout(location = 0, index = 1) out vec4 outSrc1;441layout(location = 0, index = 0) out vec4 outSrc0;442void main() {443outSrc0 = src0;444outSrc1 = src1;445})";446447makeProgram(essl3_shaders::vs::Simple(), kFragColorShader);448449checkOutputIndexQuery("outSrc0", 0);450checkOutputIndexQuery("outSrc1", 1);451452drawTest();453}454455// Test an ESSL 3.00 shader that uses two fragment outputs with locations specified through the API.456TEST_P(EXTBlendFuncExtendedDrawTestES3, FragmentOutputLocationAPI)457{458ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));459460constexpr char kFS[] = R"(#version 300 es461#extension GL_EXT_blend_func_extended : require462precision mediump float;463uniform vec4 src0;464uniform vec4 src1;465out vec4 outSrc1;466out vec4 outSrc0;467void main() {468outSrc0 = src0;469outSrc1 = src1;470})";471472mProgram = CompileProgram(essl3_shaders::vs::Simple(), kFS, [](GLuint program) {473glBindFragDataLocationIndexedEXT(program, 0, 0, "outSrc0");474glBindFragDataLocationIndexedEXT(program, 0, 1, "outSrc1");475});476477ASSERT_NE(0u, mProgram);478479checkOutputIndexQuery("outSrc0", 0);480checkOutputIndexQuery("outSrc1", 1);481482drawTest();483}484485// Test an ESSL 3.00 shader that uses two fragment outputs, with location for one specified through486// the API and location for another being set automatically.487TEST_P(EXTBlendFuncExtendedDrawTestES3, FragmentOutputLocationsAPIAndAutomatic)488{489ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));490491constexpr char kFS[] = R"(#version 300 es492#extension GL_EXT_blend_func_extended : require493precision mediump float;494uniform vec4 src0;495uniform vec4 src1;496out vec4 outSrc1;497out vec4 outSrc0;498void main() {499outSrc0 = src0;500outSrc1 = src1;501})";502503mProgram = CompileProgram(essl3_shaders::vs::Simple(), kFS, [](GLuint program) {504glBindFragDataLocationIndexedEXT(program, 0, 1, "outSrc1");505});506507ASSERT_NE(0u, mProgram);508509checkOutputIndexQuery("outSrc0", 0);510checkOutputIndexQuery("outSrc1", 1);511512drawTest();513}514515// Test an ESSL 3.00 shader that uses two array fragment outputs with locations specified through516// the API.517TEST_P(EXTBlendFuncExtendedDrawTestES3, FragmentArrayOutputLocationsAPI)518{519ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));520521// TODO: Investigate this mac-only failure. http://angleproject.com/1085522ANGLE_SKIP_TEST_IF(IsOSX());523524// Suspected VK driver bug http://anglebug.com/5523525ANGLE_SKIP_TEST_IF(IsVulkan() && (IsNVIDIA() || IsPixel2()));526527constexpr char kFS[] = R"(#version 300 es528#extension GL_EXT_blend_func_extended : require529precision mediump float;530uniform vec4 src0;531uniform vec4 src1;532out vec4 outSrc1[1];533out vec4 outSrc0[1];534void main() {535outSrc0[0] = src0;536outSrc1[0] = src1;537})";538539mProgram = CompileProgram(essl3_shaders::vs::Simple(), kFS, [](GLuint program) {540// Specs aren't very clear on what kind of name should be used when binding location for541// array variables. We only allow names that do include the "[0]" suffix.542glBindFragDataLocationIndexedEXT(program, 0, 0, "outSrc0[0]");543glBindFragDataLocationIndexedEXT(program, 0, 1, "outSrc1[0]");544});545546ASSERT_NE(0u, mProgram);547548// The extension spec is not very clear on what name can be used for the queries for array549// variables. We're checking that the queries work in the same way as specified in OpenGL 4.4550// page 107.551checkOutputIndexQuery("outSrc0[0]", 0);552checkOutputIndexQuery("outSrc1[0]", 1);553checkOutputIndexQuery("outSrc0", 0);554checkOutputIndexQuery("outSrc1", 1);555556// These queries use an out of range array index so they should return -1.557checkOutputIndexQuery("outSrc0[1]", -1);558checkOutputIndexQuery("outSrc1[1]", -1);559560drawTest();561}562563// Ported from TranslatorVariants/EXTBlendFuncExtendedES3DrawTest564// Test that tests glBindFragDataLocationEXT, glBindFragDataLocationIndexedEXT,565// glGetFragDataLocation, glGetFragDataIndexEXT work correctly with566// GLSL array output variables. The output variable can be bound by567// referring to the variable name with or without the first element array568// accessor. The getters can query location of the individual elements in569// the array. The test does not actually use the base test drawing,570// since the drivers at the time of writing do not support multiple571// buffers and dual source blending.572TEST_P(EXTBlendFuncExtendedDrawTestES3, ES3GettersArray)573{574ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));575576// TODO(zmo): Figure out why this fails on AMD. crbug.com/585132.577// Also fails on the Intel Mesa driver, see578// https://bugs.freedesktop.org/show_bug.cgi?id=96765579ANGLE_SKIP_TEST_IF(IsLinux() && IsAMD());580ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel());581582const GLint kTestArraySize = 2;583const GLint kFragData0Location = 2;584const GLint kFragData1Location = 1;585const GLint kUnusedLocation = 5;586587// The test binds kTestArraySize -sized array to location 1 for test purposes.588// The GL_MAX_DRAW_BUFFERS must be > kTestArraySize, since an589// array will be bound to continuous locations, starting from the first590// location.591GLint maxDrawBuffers = 0;592glGetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &maxDrawBuffers);593EXPECT_LT(kTestArraySize, maxDrawBuffers);594595constexpr char kFragColorShader[] = R"(#version 300 es596#extension GL_EXT_blend_func_extended : require597precision mediump float;598uniform vec4 src;599uniform vec4 src1;600out vec4 FragData[2];601void main() {602FragData[0] = src;603FragData[1] = src1;604})";605606struct testCase607{608std::string unusedLocationName;609std::string fragData0LocationName;610std::string fragData1LocationName;611};612613testCase testCases[4]{{"FragData[0]", "FragData", "FragData[1]"},614{"FragData", "FragData[0]", "FragData[1]"},615{"FragData[0]", "FragData", "FragData[1]"},616{"FragData", "FragData[0]", "FragData[1]"}};617618for (const testCase &test : testCases)619{620mProgram =621CompileProgram(essl3_shaders::vs::Simple(), kFragColorShader, [&](GLuint program) {622glBindFragDataLocationEXT(program, kUnusedLocation,623test.unusedLocationName.c_str());624glBindFragDataLocationEXT(program, kFragData0Location,625test.fragData0LocationName.c_str());626glBindFragDataLocationEXT(program, kFragData1Location,627test.fragData1LocationName.c_str());628});629630EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());631LinkProgram();632EXPECT_EQ(kFragData0Location, glGetFragDataLocation(mProgram, "FragData"));633EXPECT_EQ(0, glGetFragDataIndexEXT(mProgram, "FragData"));634EXPECT_EQ(kFragData0Location, glGetFragDataLocation(mProgram, "FragData[0]"));635EXPECT_EQ(0, glGetFragDataIndexEXT(mProgram, "FragData[0]"));636EXPECT_EQ(kFragData1Location, glGetFragDataLocation(mProgram, "FragData[1]"));637EXPECT_EQ(0, glGetFragDataIndexEXT(mProgram, "FragData[1]"));638// Index bigger than the GLSL variable array length does not find anything.639EXPECT_EQ(-1, glGetFragDataLocation(mProgram, "FragData[3]"));640}641}642643// Ported from TranslatorVariants/EXTBlendFuncExtendedES3DrawTest644TEST_P(EXTBlendFuncExtendedDrawTestES3, ESSL3BindSimpleVarAsArrayNoBind)645{646ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));647648constexpr char kFragDataShader[] = R"(#version 300 es649#extension GL_EXT_blend_func_extended : require650precision mediump float;651uniform vec4 src;652uniform vec4 src1;653out vec4 FragData;654out vec4 SecondaryFragData;655void main() {656FragData = src;657SecondaryFragData = src1;658})";659660mProgram = CompileProgram(essl3_shaders::vs::Simple(), kFragDataShader, [](GLuint program) {661glBindFragDataLocationEXT(program, 0, "FragData[0]");662glBindFragDataLocationIndexedEXT(program, 0, 1, "SecondaryFragData[0]");663});664665LinkProgram();666667EXPECT_EQ(-1, glGetFragDataLocation(mProgram, "FragData[0]"));668EXPECT_EQ(0, glGetFragDataLocation(mProgram, "FragData"));669EXPECT_EQ(1, glGetFragDataLocation(mProgram, "SecondaryFragData"));670// Did not bind index.671EXPECT_EQ(0, glGetFragDataIndexEXT(mProgram, "SecondaryFragData"));672673glBindFragDataLocationEXT(mProgram, 0, "FragData");674glBindFragDataLocationIndexedEXT(mProgram, 0, 1, "SecondaryFragData");675LinkProgram();676}677678// Test an ESSL 3.00 program with a link-time fragment output location conflict.679TEST_P(EXTBlendFuncExtendedTestES3, FragmentOutputLocationConflict)680{681ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));682683constexpr char kFS[] = R"(#version 300 es684#extension GL_EXT_blend_func_extended : require685precision mediump float;686uniform vec4 src0;687uniform vec4 src1;688out vec4 out0;689out vec4 out1;690void main() {691out0 = src0;692out1 = src1;693})";694695GLuint vs = CompileShader(GL_VERTEX_SHADER, essl3_shaders::vs::Simple());696GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);697ASSERT_NE(0u, vs);698ASSERT_NE(0u, fs);699700GLuint program = glCreateProgram();701glAttachShader(program, vs);702glDeleteShader(vs);703glAttachShader(program, fs);704glDeleteShader(fs);705706glBindFragDataLocationIndexedEXT(program, 0, 0, "out0");707glBindFragDataLocationIndexedEXT(program, 0, 0, "out1");708709// The program should fail to link.710glLinkProgram(program);711GLint linkStatus;712glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);713EXPECT_EQ(0, linkStatus);714715glDeleteProgram(program);716}717718// Test an ESSL 3.00 program with some bindings set for nonexistent variables. These should not719// create link-time conflicts.720TEST_P(EXTBlendFuncExtendedTestES3, FragmentOutputLocationForNonexistentOutput)721{722ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));723724constexpr char kFS[] = R"(#version 300 es725#extension GL_EXT_blend_func_extended : require726precision mediump float;727uniform vec4 src0;728out vec4 out0;729void main() {730out0 = src0;731})";732733GLuint vs = CompileShader(GL_VERTEX_SHADER, essl3_shaders::vs::Simple());734GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);735ASSERT_NE(0u, vs);736ASSERT_NE(0u, fs);737738GLuint program = glCreateProgram();739glAttachShader(program, vs);740glDeleteShader(vs);741glAttachShader(program, fs);742glDeleteShader(fs);743744glBindFragDataLocationIndexedEXT(program, 0, 0, "out0");745glBindFragDataLocationIndexedEXT(program, 0, 0, "out1");746glBindFragDataLocationIndexedEXT(program, 0, 0, "out2[0]");747748// The program should link successfully - conflicting location for nonexistent variables out1 or749// out2 should not be an issue.750glLinkProgram(program);751GLint linkStatus;752glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);753EXPECT_NE(0, linkStatus);754755glDeleteProgram(program);756}757758// Test mixing shader-assigned and automatic output locations.759TEST_P(EXTBlendFuncExtendedTestES3, FragmentOutputLocationsPartiallyAutomatic)760{761ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));762763GLint maxDrawBuffers;764glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);765ANGLE_SKIP_TEST_IF(maxDrawBuffers < 4);766767constexpr char kFS[] = R"(#version 300 es768#extension GL_EXT_blend_func_extended : require769precision mediump float;770uniform vec4 src0;771uniform vec4 src1;772uniform vec4 src2;773uniform vec4 src3;774layout(location=0) out vec4 out0;775layout(location=3) out vec4 out3;776out vec4 out12[2];777void main() {778out0 = src0;779out12[0] = src1;780out12[1] = src2;781out3 = src3;782})";783784GLuint program = CompileProgram(essl3_shaders::vs::Simple(), kFS);785ASSERT_NE(0u, program);786787GLint location = glGetFragDataLocation(program, "out0");788EXPECT_EQ(0, location);789location = glGetFragDataLocation(program, "out12");790EXPECT_EQ(1, location);791location = glGetFragDataLocation(program, "out3");792EXPECT_EQ(3, location);793794glDeleteProgram(program);795}796797// Test a fragment output array that doesn't fit because contiguous locations are not available.798TEST_P(EXTBlendFuncExtendedTestES3, FragmentOutputArrayDoesntFit)799{800ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));801802GLint maxDrawBuffers;803glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);804ANGLE_SKIP_TEST_IF(maxDrawBuffers < 4);805806std::stringstream fragShader;807fragShader << R"(#version 300 es808#extension GL_EXT_blend_func_extended : require809precision mediump float;810layout(location=2) out vec4 out0;811out vec4 outArray[)"812<< (maxDrawBuffers - 1) << R"(];813void main() {814out0 = vec4(1.0);815outArray[0] = vec4(1.0);816})";817818GLuint vs = CompileShader(GL_VERTEX_SHADER, essl3_shaders::vs::Simple());819GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fragShader.str().c_str());820ASSERT_NE(0u, vs);821ASSERT_NE(0u, fs);822823GLuint program = glCreateProgram();824glAttachShader(program, vs);825glDeleteShader(vs);826glAttachShader(program, fs);827glDeleteShader(fs);828829// The program should not link - there's no way to fit "outArray" into available output830// locations.831glLinkProgram(program);832GLint linkStatus;833glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);834EXPECT_EQ(0, linkStatus);835836glDeleteProgram(program);837}838839// Use a program pipeline with EXT_blend_func_extended840TEST_P(EXTBlendFuncExtendedDrawTestES31, UseProgramPipeline)841{842// Only the Vulkan backend supports PPO843ANGLE_SKIP_TEST_IF(!IsVulkan());844845// Create two separable program objects from a846// single source string respectively (vertSrc and fragSrc)847ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));848849const char *kFragColorShader = R"(#version 300 es850#extension GL_EXT_blend_func_extended : require851precision mediump float;852uniform vec4 src0;853uniform vec4 src1;854layout(location = 0, index = 1) out vec4 outSrc1;855layout(location = 0, index = 0) out vec4 outSrc0;856void main() {857outSrc0 = src0;858outSrc1 = src1;859})";860861setupProgramPipeline(essl3_shaders::vs::Simple(), kFragColorShader);862863checkOutputIndexQuery("outSrc0", 0);864checkOutputIndexQuery("outSrc1", 1);865866ASSERT_EQ(mProgram, 0u);867drawTest();868869ASSERT_GL_NO_ERROR();870}871872// Use program pipeline where the fragment program is changed873TEST_P(EXTBlendFuncExtendedDrawTestES31, UseTwoProgramStages)874{875// Only the Vulkan backend supports PPO876ANGLE_SKIP_TEST_IF(!IsVulkan());877878// Create two separable program objects from a879// single source string respectively (vertSrc and fragSrc)880ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_blend_func_extended"));881882const char *kFragColorShaderFlipped = R"(#version 300 es883#extension GL_EXT_blend_func_extended : require884precision mediump float;885uniform vec4 src0;886uniform vec4 src1;887layout(location = 0, index = 0) out vec4 outSrc1;888layout(location = 0, index = 1) out vec4 outSrc0;889void main() {890outSrc0 = src0;891outSrc1 = src1;892})";893894const char *kFragColorShader = R"(#version 300 es895#extension GL_EXT_blend_func_extended : require896precision mediump float;897uniform vec4 src0;898uniform vec4 src1;899layout(location = 0, index = 1) out vec4 outSrc1;900layout(location = 0, index = 0) out vec4 outSrc0;901void main() {902outSrc0 = src0;903outSrc1 = src1;904})";905906setupProgramPipeline(essl3_shaders::vs::Simple(), kFragColorShaderFlipped);907908// Check index values frag shader with the "flipped" index values909checkOutputIndexQuery("outSrc0", 1);910checkOutputIndexQuery("outSrc1", 0);911912GLuint previousProgram = mFragProgram;913mFragProgram = createShaderProgram(GL_FRAGMENT_SHADER, kFragColorShader);914ASSERT_NE(mFragProgram, 0u);915916// Change the Fragment program of the pipeline917glUseProgramStages(mPipeline, GL_FRAGMENT_SHADER_BIT, mFragProgram);918EXPECT_GL_NO_ERROR();919920checkOutputIndexQuery("outSrc0", 0);921checkOutputIndexQuery("outSrc1", 1);922923ASSERT_EQ(mProgram, 0u);924drawTest();925926if (previousProgram)927{928glDeleteProgram(previousProgram);929}930ASSERT_GL_NO_ERROR();931}932933ANGLE_INSTANTIATE_TEST_ES2(EXTBlendFuncExtendedTest);934935GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EXTBlendFuncExtendedTestES3);936ANGLE_INSTANTIATE_TEST_ES3_AND_ES31(EXTBlendFuncExtendedTestES3);937938ANGLE_INSTANTIATE_TEST_ES2(EXTBlendFuncExtendedDrawTest);939940GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EXTBlendFuncExtendedDrawTestES3);941ANGLE_INSTANTIATE_TEST_ES3_AND_ES31(EXTBlendFuncExtendedDrawTestES3);942943GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EXTBlendFuncExtendedDrawTestES31);944ANGLE_INSTANTIATE_TEST_ES31(EXTBlendFuncExtendedDrawTestES31);945946947