Path: blob/main_old/src/tests/compiler_tests/CollectVariables_test.cpp
1693 views
//1// Copyright 2014 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// CollectVariables_test.cpp:6// Some tests for shader inspection7//89#include <memory>1011#include "GLSLANG/ShaderLang.h"12#include "angle_gl.h"13#include "compiler/translator/TranslatorGLSL.h"14#include "gtest/gtest.h"1516using namespace sh;1718#define EXPECT_GLENUM_EQ(expected, actual) \19EXPECT_EQ(static_cast<::GLenum>(expected), static_cast<::GLenum>(actual))2021namespace22{2324std::string DecorateName(const char *name)25{26return std::string("_u") + name;27}2829} // anonymous namespace3031class CollectVariablesTest : public testing::Test32{33public:34CollectVariablesTest(::GLenum shaderType) : mShaderType(shaderType) {}3536protected:37void SetUp() override38{39ShBuiltInResources resources;40InitBuiltInResources(&resources);41resources.MaxDrawBuffers = 8;42resources.EXT_blend_func_extended = true;43resources.MaxDualSourceDrawBuffers = 1;4445initTranslator(resources);46}4748virtual void initTranslator(const ShBuiltInResources &resources)49{50mTranslator.reset(51new TranslatorGLSL(mShaderType, SH_GLES3_SPEC, SH_GLSL_COMPATIBILITY_OUTPUT));52ASSERT_TRUE(mTranslator->Init(resources));53}5455// For use in the gl_DepthRange tests.56void validateDepthRangeShader(const std::string &shaderString)57{58const char *shaderStrings[] = {shaderString.c_str()};59ASSERT_TRUE(mTranslator->compile(shaderStrings, 1, SH_VARIABLES));6061const std::vector<ShaderVariable> &uniforms = mTranslator->getUniforms();62ASSERT_EQ(1u, uniforms.size());6364const ShaderVariable &uniform = uniforms[0];65EXPECT_EQ("gl_DepthRange", uniform.name);66ASSERT_TRUE(uniform.isStruct());67ASSERT_EQ(3u, uniform.fields.size());6869bool foundNear = false;70bool foundFar = false;71bool foundDiff = false;7273for (const auto &field : uniform.fields)74{75if (field.name == "near")76{77EXPECT_FALSE(foundNear);78foundNear = true;79}80else if (field.name == "far")81{82EXPECT_FALSE(foundFar);83foundFar = true;84}85else86{87ASSERT_EQ("diff", field.name);88EXPECT_FALSE(foundDiff);89foundDiff = true;90}9192EXPECT_FALSE(field.isArray());93EXPECT_FALSE(field.isStruct());94EXPECT_GLENUM_EQ(GL_HIGH_FLOAT, field.precision);95EXPECT_TRUE(field.staticUse);96EXPECT_GLENUM_EQ(GL_FLOAT, field.type);97}9899EXPECT_TRUE(foundNear && foundFar && foundDiff);100}101102// For use in tests for output varibles.103void validateOutputVariableForShader(const std::string &shaderString,104unsigned int varIndex,105const char *varName,106const ShaderVariable **outResult)107{108const char *shaderStrings[] = {shaderString.c_str()};109ASSERT_TRUE(mTranslator->compile(shaderStrings, 1, SH_VARIABLES))110<< mTranslator->getInfoSink().info.str();111112const auto &outputVariables = mTranslator->getOutputVariables();113ASSERT_LT(varIndex, outputVariables.size());114const ShaderVariable &outputVariable = outputVariables[varIndex];115EXPECT_EQ(-1, outputVariable.location);116EXPECT_TRUE(outputVariable.staticUse);117EXPECT_TRUE(outputVariable.active);118EXPECT_EQ(varName, outputVariable.name);119*outResult = &outputVariable;120}121122void compile(const std::string &shaderString, ShCompileOptions compileOptions)123{124const char *shaderStrings[] = {shaderString.c_str()};125ASSERT_TRUE(mTranslator->compile(shaderStrings, 1, SH_VARIABLES | compileOptions));126}127128void compile(const std::string &shaderString) { compile(shaderString, 0u); }129130void checkUniformStaticallyUsedButNotActive(const char *name)131{132const auto &uniforms = mTranslator->getUniforms();133ASSERT_EQ(1u, uniforms.size());134135const ShaderVariable &uniform = uniforms[0];136EXPECT_EQ(name, uniform.name);137EXPECT_TRUE(uniform.staticUse);138EXPECT_FALSE(uniform.active);139}140141::GLenum mShaderType;142std::unique_ptr<TranslatorGLSL> mTranslator;143};144145class CollectVertexVariablesTest : public CollectVariablesTest146{147public:148CollectVertexVariablesTest() : CollectVariablesTest(GL_VERTEX_SHADER) {}149};150151class CollectFragmentVariablesTest : public CollectVariablesTest152{153public:154CollectFragmentVariablesTest() : CollectVariablesTest(GL_FRAGMENT_SHADER) {}155};156157class CollectVariablesTestES31 : public CollectVariablesTest158{159public:160CollectVariablesTestES31(sh::GLenum shaderType) : CollectVariablesTest(shaderType) {}161162protected:163void initTranslator(const ShBuiltInResources &resources) override164{165mTranslator.reset(166new TranslatorGLSL(mShaderType, SH_GLES3_1_SPEC, SH_GLSL_COMPATIBILITY_OUTPUT));167ASSERT_TRUE(mTranslator->Init(resources));168}169};170171class CollectVariablesEXTGeometryShaderTest : public CollectVariablesTestES31172{173public:174CollectVariablesEXTGeometryShaderTest(sh::GLenum shaderType)175: CollectVariablesTestES31(shaderType)176{}177178protected:179void SetUp() override180{181ShBuiltInResources resources;182InitBuiltInResources(&resources);183resources.EXT_geometry_shader = 1;184185initTranslator(resources);186}187};188189class CollectGeometryVariablesTest : public CollectVariablesEXTGeometryShaderTest190{191public:192CollectGeometryVariablesTest() : CollectVariablesEXTGeometryShaderTest(GL_GEOMETRY_SHADER_EXT)193{}194195protected:196void compileGeometryShaderWithInputPrimitive(const std::string &inputPrimitive,197const std::string &inputVarying,198const std::string &functionBody)199{200std::ostringstream sstream;201sstream << "#version 310 es\n"202<< "#extension GL_EXT_geometry_shader : require\n"203<< "layout (" << inputPrimitive << ") in;\n"204<< "layout (points, max_vertices = 2) out;\n"205<< inputVarying << functionBody;206207compile(sstream.str());208}209};210211class CollectFragmentVariablesEXTGeometryShaderTest : public CollectVariablesEXTGeometryShaderTest212{213public:214CollectFragmentVariablesEXTGeometryShaderTest()215: CollectVariablesEXTGeometryShaderTest(GL_FRAGMENT_SHADER)216{}217218protected:219void initTranslator(const ShBuiltInResources &resources)220{221mTranslator.reset(222new TranslatorGLSL(mShaderType, SH_GLES3_1_SPEC, SH_GLSL_COMPATIBILITY_OUTPUT));223ASSERT_TRUE(mTranslator->Init(resources));224}225};226227class CollectVertexVariablesES31Test : public CollectVariablesTestES31228{229public:230CollectVertexVariablesES31Test() : CollectVariablesTestES31(GL_VERTEX_SHADER) {}231};232233class CollectFragmentVariablesES31Test : public CollectVariablesTestES31234{235public:236CollectFragmentVariablesES31Test() : CollectVariablesTestES31(GL_FRAGMENT_SHADER) {}237};238239TEST_F(CollectFragmentVariablesTest, SimpleOutputVar)240{241const std::string &shaderString =242"#version 300 es\n"243"precision mediump float;\n"244"out vec4 out_fragColor;\n"245"void main() {\n"246" out_fragColor = vec4(1.0);\n"247"}\n";248249compile(shaderString);250251const auto &outputVariables = mTranslator->getOutputVariables();252ASSERT_EQ(1u, outputVariables.size());253254const ShaderVariable &outputVariable = outputVariables[0];255256EXPECT_FALSE(outputVariable.isArray());257EXPECT_EQ(-1, outputVariable.location);258EXPECT_GLENUM_EQ(GL_MEDIUM_FLOAT, outputVariable.precision);259EXPECT_TRUE(outputVariable.staticUse);260EXPECT_TRUE(outputVariable.active);261EXPECT_GLENUM_EQ(GL_FLOAT_VEC4, outputVariable.type);262EXPECT_EQ("out_fragColor", outputVariable.name);263}264265TEST_F(CollectFragmentVariablesTest, LocationOutputVar)266{267const std::string &shaderString =268"#version 300 es\n"269"precision mediump float;\n"270"layout(location=5) out vec4 out_fragColor;\n"271"void main() {\n"272" out_fragColor = vec4(1.0);\n"273"}\n";274275compile(shaderString);276277const auto &outputVariables = mTranslator->getOutputVariables();278ASSERT_EQ(1u, outputVariables.size());279280const ShaderVariable &outputVariable = outputVariables[0];281282EXPECT_FALSE(outputVariable.isArray());283EXPECT_EQ(5, outputVariable.location);284EXPECT_GLENUM_EQ(GL_MEDIUM_FLOAT, outputVariable.precision);285EXPECT_TRUE(outputVariable.staticUse);286EXPECT_TRUE(outputVariable.active);287EXPECT_GLENUM_EQ(GL_FLOAT_VEC4, outputVariable.type);288EXPECT_EQ("out_fragColor", outputVariable.name);289}290291TEST_F(CollectVertexVariablesTest, LocationAttribute)292{293const std::string &shaderString =294"#version 300 es\n"295"layout(location=5) in vec4 in_Position;\n"296"void main() {\n"297" gl_Position = in_Position;\n"298"}\n";299300compile(shaderString);301302const std::vector<ShaderVariable> &attributes = mTranslator->getAttributes();303ASSERT_EQ(1u, attributes.size());304305const ShaderVariable &attribute = attributes[0];306307EXPECT_FALSE(attribute.isArray());308EXPECT_EQ(5, attribute.location);309EXPECT_GLENUM_EQ(GL_HIGH_FLOAT, attribute.precision);310EXPECT_TRUE(attribute.staticUse);311EXPECT_TRUE(attribute.active);312EXPECT_GLENUM_EQ(GL_FLOAT_VEC4, attribute.type);313EXPECT_EQ("in_Position", attribute.name);314}315316TEST_F(CollectVertexVariablesTest, SimpleInterfaceBlock)317{318const std::string &shaderString =319"#version 300 es\n"320"uniform b {\n"321" float f;\n"322"};"323"void main() {\n"324" gl_Position = vec4(f, 0.0, 0.0, 1.0);\n"325"}\n";326327compile(shaderString);328329const std::vector<InterfaceBlock> &interfaceBlocks = mTranslator->getInterfaceBlocks();330ASSERT_EQ(1u, interfaceBlocks.size());331332const InterfaceBlock &interfaceBlock = interfaceBlocks[0];333334EXPECT_EQ(0u, interfaceBlock.arraySize);335EXPECT_EQ(BLOCKLAYOUT_SHARED, interfaceBlock.layout);336EXPECT_EQ("b", interfaceBlock.name);337EXPECT_TRUE(interfaceBlock.staticUse);338EXPECT_TRUE(interfaceBlock.active);339340ASSERT_EQ(1u, interfaceBlock.fields.size());341342const ShaderVariable &field = interfaceBlock.fields[0];343344EXPECT_GLENUM_EQ(GL_HIGH_FLOAT, field.precision);345EXPECT_TRUE(field.staticUse);346EXPECT_TRUE(field.active);347EXPECT_GLENUM_EQ(GL_FLOAT, field.type);348EXPECT_EQ("f", field.name);349EXPECT_FALSE(field.isRowMajorLayout);350EXPECT_TRUE(field.fields.empty());351}352353TEST_F(CollectVertexVariablesTest, SimpleInstancedInterfaceBlock)354{355const std::string &shaderString =356"#version 300 es\n"357"uniform b {\n"358" float f;\n"359"} blockInstance;"360"void main() {\n"361" gl_Position = vec4(blockInstance.f, 0.0, 0.0, 1.0);\n"362"}\n";363364compile(shaderString);365366const std::vector<InterfaceBlock> &interfaceBlocks = mTranslator->getInterfaceBlocks();367ASSERT_EQ(1u, interfaceBlocks.size());368369const InterfaceBlock &interfaceBlock = interfaceBlocks[0];370371EXPECT_EQ(0u, interfaceBlock.arraySize);372EXPECT_EQ(BLOCKLAYOUT_SHARED, interfaceBlock.layout);373EXPECT_EQ("b", interfaceBlock.name);374EXPECT_EQ("blockInstance", interfaceBlock.instanceName);375EXPECT_TRUE(interfaceBlock.staticUse);376EXPECT_TRUE(interfaceBlock.active);377378ASSERT_EQ(1u, interfaceBlock.fields.size());379380const ShaderVariable &field = interfaceBlock.fields[0];381382EXPECT_GLENUM_EQ(GL_HIGH_FLOAT, field.precision);383EXPECT_TRUE(field.staticUse);384EXPECT_TRUE(field.active);385EXPECT_GLENUM_EQ(GL_FLOAT, field.type);386EXPECT_EQ("f", field.name);387EXPECT_FALSE(field.isRowMajorLayout);388EXPECT_TRUE(field.fields.empty());389}390391TEST_F(CollectVertexVariablesTest, StructInterfaceBlock)392{393const std::string &shaderString =394"#version 300 es\n"395"struct st { float f; };"396"uniform b {\n"397" st s;\n"398"};"399"void main() {\n"400" gl_Position = vec4(s.f, 0.0, 0.0, 1.0);\n"401"}\n";402403compile(shaderString);404405const std::vector<InterfaceBlock> &interfaceBlocks = mTranslator->getInterfaceBlocks();406ASSERT_EQ(1u, interfaceBlocks.size());407408const InterfaceBlock &interfaceBlock = interfaceBlocks[0];409410EXPECT_EQ(0u, interfaceBlock.arraySize);411EXPECT_EQ(BLOCKLAYOUT_SHARED, interfaceBlock.layout);412EXPECT_EQ("b", interfaceBlock.name);413EXPECT_EQ(DecorateName("b"), interfaceBlock.mappedName);414EXPECT_TRUE(interfaceBlock.staticUse);415EXPECT_TRUE(interfaceBlock.active);416417ASSERT_EQ(1u, interfaceBlock.fields.size());418419const ShaderVariable &blockField = interfaceBlock.fields[0];420421EXPECT_TRUE(blockField.isStruct());422EXPECT_TRUE(blockField.staticUse);423EXPECT_TRUE(blockField.active);424EXPECT_EQ("s", blockField.name);425EXPECT_EQ(DecorateName("s"), blockField.mappedName);426EXPECT_FALSE(blockField.isRowMajorLayout);427428const ShaderVariable &structField = blockField.fields[0];429430// NOTE: we don't track static use or active at individual struct member granularity.431EXPECT_FALSE(structField.isStruct());432EXPECT_EQ("f", structField.name);433EXPECT_EQ(DecorateName("f"), structField.mappedName);434EXPECT_GLENUM_EQ(GL_FLOAT, structField.type);435EXPECT_GLENUM_EQ(GL_HIGH_FLOAT, structField.precision);436}437438TEST_F(CollectVertexVariablesTest, StructInstancedInterfaceBlock)439{440const std::string &shaderString =441"#version 300 es\n"442"struct st { float f; };"443"uniform b {\n"444" st s;\n"445"} instanceName;"446"void main() {\n"447" gl_Position = vec4(instanceName.s.f, 0.0, 0.0, 1.0);\n"448"}\n";449450compile(shaderString);451452const std::vector<InterfaceBlock> &interfaceBlocks = mTranslator->getInterfaceBlocks();453ASSERT_EQ(1u, interfaceBlocks.size());454455const InterfaceBlock &interfaceBlock = interfaceBlocks[0];456457EXPECT_EQ(0u, interfaceBlock.arraySize);458EXPECT_EQ(BLOCKLAYOUT_SHARED, interfaceBlock.layout);459EXPECT_EQ("b", interfaceBlock.name);460EXPECT_EQ(DecorateName("b"), interfaceBlock.mappedName);461EXPECT_EQ("instanceName", interfaceBlock.instanceName);462EXPECT_TRUE(interfaceBlock.staticUse);463EXPECT_TRUE(interfaceBlock.active);464465ASSERT_EQ(1u, interfaceBlock.fields.size());466467const ShaderVariable &blockField = interfaceBlock.fields[0];468469EXPECT_TRUE(blockField.isStruct());470EXPECT_TRUE(blockField.staticUse);471EXPECT_TRUE(blockField.active);472EXPECT_EQ("s", blockField.name);473EXPECT_EQ(DecorateName("s"), blockField.mappedName);474EXPECT_FALSE(blockField.isRowMajorLayout);475476const ShaderVariable &structField = blockField.fields[0];477478// NOTE: we don't track static use or active at individual struct member granularity.479EXPECT_FALSE(structField.isStruct());480EXPECT_EQ("f", structField.name);481EXPECT_EQ(DecorateName("f"), structField.mappedName);482EXPECT_GLENUM_EQ(GL_FLOAT, structField.type);483EXPECT_GLENUM_EQ(GL_HIGH_FLOAT, structField.precision);484}485486TEST_F(CollectVertexVariablesTest, NestedStructRowMajorInterfaceBlock)487{488const std::string &shaderString =489"#version 300 es\n"490"struct st { mat2 m; };"491"layout(row_major) uniform b {\n"492" st s;\n"493"};"494"void main() {\n"495" gl_Position = vec4(s.m);\n"496"}\n";497498compile(shaderString);499500const std::vector<InterfaceBlock> &interfaceBlocks = mTranslator->getInterfaceBlocks();501ASSERT_EQ(1u, interfaceBlocks.size());502503const InterfaceBlock &interfaceBlock = interfaceBlocks[0];504505EXPECT_EQ(0u, interfaceBlock.arraySize);506EXPECT_EQ(BLOCKLAYOUT_SHARED, interfaceBlock.layout);507EXPECT_EQ("b", interfaceBlock.name);508EXPECT_EQ(DecorateName("b"), interfaceBlock.mappedName);509EXPECT_TRUE(interfaceBlock.staticUse);510EXPECT_TRUE(interfaceBlock.active);511512ASSERT_EQ(1u, interfaceBlock.fields.size());513514const ShaderVariable &blockField = interfaceBlock.fields[0];515516EXPECT_TRUE(blockField.isStruct());517EXPECT_TRUE(blockField.staticUse);518EXPECT_TRUE(blockField.active);519EXPECT_EQ("s", blockField.name);520EXPECT_EQ(DecorateName("s"), blockField.mappedName);521EXPECT_TRUE(blockField.isRowMajorLayout);522523const ShaderVariable &structField = blockField.fields[0];524525// NOTE: we don't track static use or active at individual struct member granularity.526EXPECT_FALSE(structField.isStruct());527EXPECT_EQ("m", structField.name);528EXPECT_EQ(DecorateName("m"), structField.mappedName);529EXPECT_GLENUM_EQ(GL_FLOAT_MAT2, structField.type);530EXPECT_GLENUM_EQ(GL_HIGH_FLOAT, structField.precision);531}532533TEST_F(CollectVertexVariablesTest, VaryingInterpolation)534{535const std::string &shaderString =536"#version 300 es\n"537"precision mediump float;\n"538"centroid out float vary;\n"539"void main() {\n"540" gl_Position = vec4(1.0);\n"541" vary = 1.0;\n"542"}\n";543544compile(shaderString);545546const std::vector<ShaderVariable> &varyings = mTranslator->getOutputVaryings();547ASSERT_EQ(2u, varyings.size());548549const ShaderVariable *varying = &varyings[0];550551if (varying->name == "gl_Position")552{553varying = &varyings[1];554}555556EXPECT_FALSE(varying->isArray());557EXPECT_GLENUM_EQ(GL_MEDIUM_FLOAT, varying->precision);558EXPECT_TRUE(varying->staticUse);559EXPECT_TRUE(varying->active);560EXPECT_GLENUM_EQ(GL_FLOAT, varying->type);561EXPECT_EQ("vary", varying->name);562EXPECT_EQ(DecorateName("vary"), varying->mappedName);563EXPECT_EQ(INTERPOLATION_CENTROID, varying->interpolation);564}565566// Test for builtin uniform "gl_DepthRange" (Vertex shader)567TEST_F(CollectVertexVariablesTest, DepthRange)568{569const std::string &shaderString =570"attribute vec4 position;\n"571"void main() {\n"572" gl_Position = position + vec4(gl_DepthRange.near, gl_DepthRange.far, "573"gl_DepthRange.diff, 1.0);\n"574"}\n";575576validateDepthRangeShader(shaderString);577}578579// Test for builtin uniform "gl_DepthRange" (Fragment shader)580TEST_F(CollectFragmentVariablesTest, DepthRange)581{582const std::string &shaderString =583"precision mediump float;\n"584"void main() {\n"585" gl_FragColor = vec4(gl_DepthRange.near, gl_DepthRange.far, gl_DepthRange.diff, 1.0);\n"586"}\n";587588validateDepthRangeShader(shaderString);589}590591// Test that gl_FragColor built-in usage in ESSL1 fragment shader is reflected in the output592// variables list.593TEST_F(CollectFragmentVariablesTest, OutputVarESSL1FragColor)594{595const std::string &fragColorShader =596"precision mediump float;\n"597"void main() {\n"598" gl_FragColor = vec4(1.0);\n"599"}\n";600601const ShaderVariable *outputVariable = nullptr;602validateOutputVariableForShader(fragColorShader, 0u, "gl_FragColor", &outputVariable);603ASSERT_NE(outputVariable, nullptr);604EXPECT_FALSE(outputVariable->isArray());605EXPECT_GLENUM_EQ(GL_FLOAT_VEC4, outputVariable->type);606EXPECT_GLENUM_EQ(GL_MEDIUM_FLOAT, outputVariable->precision);607}608609// Test that gl_FragData built-in usage in ESSL1 fragment shader is reflected in the output610// variables list.611TEST_F(CollectFragmentVariablesTest, OutputVarESSL1FragData)612{613const std::string &fragDataShader =614"#extension GL_EXT_draw_buffers : require\n"615"precision mediump float;\n"616"void main() {\n"617" gl_FragData[0] = vec4(1.0);\n"618" gl_FragData[1] = vec4(0.5);\n"619"}\n";620621ShBuiltInResources resources = mTranslator->getResources();622resources.EXT_draw_buffers = 1;623const unsigned int kMaxDrawBuffers = 3u;624resources.MaxDrawBuffers = kMaxDrawBuffers;625initTranslator(resources);626627const ShaderVariable *outputVariable = nullptr;628validateOutputVariableForShader(fragDataShader, 0u, "gl_FragData", &outputVariable);629ASSERT_NE(outputVariable, nullptr);630ASSERT_EQ(1u, outputVariable->arraySizes.size());631EXPECT_EQ(kMaxDrawBuffers, outputVariable->arraySizes.back());632EXPECT_GLENUM_EQ(GL_FLOAT_VEC4, outputVariable->type);633EXPECT_GLENUM_EQ(GL_MEDIUM_FLOAT, outputVariable->precision);634}635636// Test that gl_FragDataEXT built-in usage in ESSL1 fragment shader is reflected in the output637// variables list. Also test that the precision is mediump.638TEST_F(CollectFragmentVariablesTest, OutputVarESSL1FragDepthMediump)639{640const std::string &fragDepthShader =641"#extension GL_EXT_frag_depth : require\n"642"precision mediump float;\n"643"void main() {\n"644" gl_FragDepthEXT = 0.7;"645"}\n";646647ShBuiltInResources resources = mTranslator->getResources();648resources.EXT_frag_depth = 1;649initTranslator(resources);650651const ShaderVariable *outputVariable = nullptr;652validateOutputVariableForShader(fragDepthShader, 0u, "gl_FragDepthEXT", &outputVariable);653ASSERT_NE(outputVariable, nullptr);654EXPECT_FALSE(outputVariable->isArray());655EXPECT_GLENUM_EQ(GL_FLOAT, outputVariable->type);656EXPECT_GLENUM_EQ(GL_MEDIUM_FLOAT, outputVariable->precision);657}658659// Test that gl_FragDataEXT built-in usage in ESSL1 fragment shader is reflected in the output660// variables list. Also test that the precision is highp if user requests it.661TEST_F(CollectFragmentVariablesTest, OutputVarESSL1FragDepthHighp)662{663const std::string &fragDepthHighShader =664"#extension GL_EXT_frag_depth : require\n"665"void main() {\n"666" gl_FragDepthEXT = 0.7;"667"}\n";668669ShBuiltInResources resources = mTranslator->getResources();670resources.EXT_frag_depth = 1;671resources.FragmentPrecisionHigh = 1;672initTranslator(resources);673674const ShaderVariable *outputVariable = nullptr;675validateOutputVariableForShader(fragDepthHighShader, 0u, "gl_FragDepthEXT", &outputVariable);676ASSERT_NE(outputVariable, nullptr);677EXPECT_FALSE(outputVariable->isArray());678EXPECT_GLENUM_EQ(GL_FLOAT, outputVariable->type);679EXPECT_GLENUM_EQ(GL_HIGH_FLOAT, outputVariable->precision);680}681682// Test that gl_FragData built-in usage in ESSL3 fragment shader is reflected in the output683// variables list. Also test that the precision is highp.684TEST_F(CollectFragmentVariablesTest, OutputVarESSL3FragDepthHighp)685{686const std::string &fragDepthHighShader =687"#version 300 es\n"688"precision mediump float;\n"689"void main() {\n"690" gl_FragDepth = 0.7;"691"}\n";692693ShBuiltInResources resources = mTranslator->getResources();694resources.EXT_frag_depth = 1;695initTranslator(resources);696697const ShaderVariable *outputVariable = nullptr;698validateOutputVariableForShader(fragDepthHighShader, 0u, "gl_FragDepth", &outputVariable);699ASSERT_NE(outputVariable, nullptr);700EXPECT_FALSE(outputVariable->isArray());701EXPECT_GLENUM_EQ(GL_FLOAT, outputVariable->type);702EXPECT_GLENUM_EQ(GL_HIGH_FLOAT, outputVariable->precision);703}704705// Test that gl_SecondaryFragColorEXT built-in usage in ESSL1 fragment shader is reflected in the706// output variables list.707TEST_F(CollectFragmentVariablesTest, OutputVarESSL1EXTBlendFuncExtendedSecondaryFragColor)708{709const char *secondaryFragColorShader =710"#extension GL_EXT_blend_func_extended : require\n"711"precision mediump float;\n"712"void main() {\n"713" gl_FragColor = vec4(1.0);\n"714" gl_SecondaryFragColorEXT = vec4(1.0);\n"715"}\n";716717const unsigned int kMaxDrawBuffers = 3u;718ShBuiltInResources resources = mTranslator->getResources();719resources.EXT_blend_func_extended = 1;720resources.EXT_draw_buffers = 1;721resources.MaxDrawBuffers = kMaxDrawBuffers;722resources.MaxDualSourceDrawBuffers = resources.MaxDrawBuffers;723initTranslator(resources);724725const ShaderVariable *outputVariable = nullptr;726validateOutputVariableForShader(secondaryFragColorShader, 0u, "gl_FragColor", &outputVariable);727ASSERT_NE(outputVariable, nullptr);728EXPECT_FALSE(outputVariable->isArray());729EXPECT_GLENUM_EQ(GL_FLOAT_VEC4, outputVariable->type);730EXPECT_GLENUM_EQ(GL_MEDIUM_FLOAT, outputVariable->precision);731732outputVariable = nullptr;733validateOutputVariableForShader(secondaryFragColorShader, 1u, "gl_SecondaryFragColorEXT",734&outputVariable);735ASSERT_NE(outputVariable, nullptr);736EXPECT_FALSE(outputVariable->isArray());737EXPECT_GLENUM_EQ(GL_FLOAT_VEC4, outputVariable->type);738EXPECT_GLENUM_EQ(GL_MEDIUM_FLOAT, outputVariable->precision);739}740741// Test that gl_SecondaryFragDataEXT built-in usage in ESSL1 fragment shader is reflected in the742// output variables list.743TEST_F(CollectFragmentVariablesTest, OutputVarESSL1EXTBlendFuncExtendedSecondaryFragData)744{745const char *secondaryFragDataShader =746"#extension GL_EXT_blend_func_extended : require\n"747"#extension GL_EXT_draw_buffers : require\n"748"precision mediump float;\n"749"void main() {\n"750" gl_FragData[0] = vec4(1.0);\n"751" gl_FragData[1] = vec4(0.5);\n"752" gl_SecondaryFragDataEXT[0] = vec4(1.0);\n"753" gl_SecondaryFragDataEXT[1] = vec4(0.8);\n"754"}\n";755const unsigned int kMaxDrawBuffers = 3u;756ShBuiltInResources resources = mTranslator->getResources();757resources.EXT_blend_func_extended = 1;758resources.EXT_draw_buffers = 1;759resources.MaxDrawBuffers = kMaxDrawBuffers;760resources.MaxDualSourceDrawBuffers = resources.MaxDrawBuffers;761initTranslator(resources);762763const ShaderVariable *outputVariable = nullptr;764validateOutputVariableForShader(secondaryFragDataShader, 0u, "gl_FragData", &outputVariable);765ASSERT_NE(outputVariable, nullptr);766ASSERT_EQ(1u, outputVariable->arraySizes.size());767EXPECT_EQ(kMaxDrawBuffers, outputVariable->arraySizes.back());768EXPECT_GLENUM_EQ(GL_FLOAT_VEC4, outputVariable->type);769EXPECT_GLENUM_EQ(GL_MEDIUM_FLOAT, outputVariable->precision);770771outputVariable = nullptr;772validateOutputVariableForShader(secondaryFragDataShader, 1u, "gl_SecondaryFragDataEXT",773&outputVariable);774ASSERT_NE(outputVariable, nullptr);775ASSERT_EQ(1u, outputVariable->arraySizes.size());776EXPECT_EQ(kMaxDrawBuffers, outputVariable->arraySizes.back());777EXPECT_GLENUM_EQ(GL_FLOAT_VEC4, outputVariable->type);778EXPECT_GLENUM_EQ(GL_MEDIUM_FLOAT, outputVariable->precision);779}780781static khronos_uint64_t SimpleTestHash(const char *str, size_t len)782{783return static_cast<uint64_t>(len);784}785786class CollectHashedVertexVariablesTest : public CollectVertexVariablesTest787{788protected:789void SetUp() override790{791// Initialize the translate with a hash function792ShBuiltInResources resources;793sh::InitBuiltInResources(&resources);794resources.HashFunction = SimpleTestHash;795initTranslator(resources);796}797};798799TEST_F(CollectHashedVertexVariablesTest, InstancedInterfaceBlock)800{801const std::string &shaderString =802"#version 300 es\n"803"uniform blockName {\n"804" float field;\n"805"} blockInstance;"806"void main() {\n"807" gl_Position = vec4(blockInstance.field, 0.0, 0.0, 1.0);\n"808"}\n";809810compile(shaderString);811812const std::vector<InterfaceBlock> &interfaceBlocks = mTranslator->getInterfaceBlocks();813ASSERT_EQ(1u, interfaceBlocks.size());814815const InterfaceBlock &interfaceBlock = interfaceBlocks[0];816817EXPECT_EQ(0u, interfaceBlock.arraySize);818EXPECT_EQ(BLOCKLAYOUT_SHARED, interfaceBlock.layout);819EXPECT_EQ("blockName", interfaceBlock.name);820EXPECT_EQ("blockInstance", interfaceBlock.instanceName);821EXPECT_EQ("webgl_9", interfaceBlock.mappedName);822EXPECT_TRUE(interfaceBlock.staticUse);823EXPECT_TRUE(interfaceBlock.active);824825ASSERT_EQ(1u, interfaceBlock.fields.size());826827const ShaderVariable &field = interfaceBlock.fields[0];828829EXPECT_GLENUM_EQ(GL_HIGH_FLOAT, field.precision);830EXPECT_TRUE(field.staticUse);831EXPECT_TRUE(field.active);832EXPECT_GLENUM_EQ(GL_FLOAT, field.type);833EXPECT_EQ("field", field.name);834EXPECT_EQ("webgl_5", field.mappedName);835EXPECT_FALSE(field.isRowMajorLayout);836EXPECT_TRUE(field.fields.empty());837}838839// Test a struct uniform where the struct does have a name.840TEST_F(CollectHashedVertexVariablesTest, StructUniform)841{842const std::string &shaderString =843R"(#version 300 es844struct sType845{846float field;847};848uniform sType u;849850void main()851{852gl_Position = vec4(u.field, 0.0, 0.0, 1.0);853})";854855compile(shaderString);856857const auto &uniforms = mTranslator->getUniforms();858ASSERT_EQ(1u, uniforms.size());859860const ShaderVariable &uniform = uniforms[0];861862EXPECT_FALSE(uniform.isArray());863EXPECT_EQ("u", uniform.name);864EXPECT_EQ("webgl_1", uniform.mappedName);865EXPECT_EQ("sType", uniform.structOrBlockName);866EXPECT_TRUE(uniform.staticUse);867EXPECT_TRUE(uniform.active);868869ASSERT_EQ(1u, uniform.fields.size());870871const ShaderVariable &field = uniform.fields[0];872873EXPECT_GLENUM_EQ(GL_HIGH_FLOAT, field.precision);874// We don't yet support tracking static use per field, but fields are marked statically used in875// case the struct is.876EXPECT_TRUE(field.staticUse);877EXPECT_TRUE(field.active);878EXPECT_GLENUM_EQ(GL_FLOAT, field.type);879EXPECT_EQ("field", field.name);880EXPECT_EQ("webgl_5", field.mappedName);881EXPECT_TRUE(field.fields.empty());882}883884// Test a struct uniform where the struct doesn't have a name.885TEST_F(CollectHashedVertexVariablesTest, NamelessStructUniform)886{887const std::string &shaderString =888R"(#version 300 es889uniform struct890{891float field;892} u;893894void main()895{896gl_Position = vec4(u.field, 0.0, 0.0, 1.0);897})";898899compile(shaderString);900901const auto &uniforms = mTranslator->getUniforms();902ASSERT_EQ(1u, uniforms.size());903904const ShaderVariable &uniform = uniforms[0];905906EXPECT_FALSE(uniform.isArray());907EXPECT_EQ("u", uniform.name);908EXPECT_EQ("webgl_1", uniform.mappedName);909EXPECT_EQ("", uniform.structOrBlockName);910EXPECT_TRUE(uniform.staticUse);911EXPECT_TRUE(uniform.active);912913ASSERT_EQ(1u, uniform.fields.size());914915const ShaderVariable &field = uniform.fields[0];916917EXPECT_GLENUM_EQ(GL_HIGH_FLOAT, field.precision);918// We don't yet support tracking static use per field, but fields are marked statically used in919// case the struct is.920EXPECT_TRUE(field.staticUse);921EXPECT_TRUE(field.active);922EXPECT_GLENUM_EQ(GL_FLOAT, field.type);923EXPECT_EQ("field", field.name);924EXPECT_EQ("webgl_5", field.mappedName);925EXPECT_TRUE(field.fields.empty());926}927928// Test a uniform declaration with multiple declarators.929TEST_F(CollectFragmentVariablesTest, MultiDeclaration)930{931const std::string &shaderString =932"#version 300 es\n"933"precision mediump float;\n"934"out vec4 out_fragColor;\n"935"uniform float uA, uB;\n"936"void main()\n"937"{\n"938" vec4 color = vec4(uA, uA, uA, uB);\n"939" out_fragColor = color;\n"940"}\n";941942compile(shaderString);943944const auto &uniforms = mTranslator->getUniforms();945ASSERT_EQ(2u, uniforms.size());946947const ShaderVariable &uniform = uniforms[0];948EXPECT_FALSE(uniform.isArray());949EXPECT_GLENUM_EQ(GL_MEDIUM_FLOAT, uniform.precision);950EXPECT_TRUE(uniform.staticUse);951EXPECT_TRUE(uniform.active);952EXPECT_GLENUM_EQ(GL_FLOAT, uniform.type);953EXPECT_EQ("uA", uniform.name);954955const ShaderVariable &uniformB = uniforms[1];956EXPECT_FALSE(uniformB.isArray());957EXPECT_GLENUM_EQ(GL_MEDIUM_FLOAT, uniformB.precision);958EXPECT_TRUE(uniformB.staticUse);959EXPECT_TRUE(uniformB.active);960EXPECT_GLENUM_EQ(GL_FLOAT, uniformB.type);961EXPECT_EQ("uB", uniformB.name);962}963964// Test a uniform declaration starting with an empty declarator.965TEST_F(CollectFragmentVariablesTest, EmptyDeclarator)966{967const std::string &shaderString =968"#version 300 es\n"969"precision mediump float;\n"970"out vec4 out_fragColor;\n"971"uniform float /* empty declarator */, uB;\n"972"void main()\n"973"{\n"974" out_fragColor = vec4(uB, uB, uB, uB);\n"975"}\n";976977compile(shaderString);978979const auto &uniforms = mTranslator->getUniforms();980ASSERT_EQ(1u, uniforms.size());981982const ShaderVariable &uniformB = uniforms[0];983EXPECT_FALSE(uniformB.isArray());984EXPECT_GLENUM_EQ(GL_MEDIUM_FLOAT, uniformB.precision);985EXPECT_TRUE(uniformB.staticUse);986EXPECT_TRUE(uniformB.active);987EXPECT_GLENUM_EQ(GL_FLOAT, uniformB.type);988EXPECT_EQ("uB", uniformB.name);989}990991// Test collecting variables from an instanced multiview shader that has an internal ViewID_OVR992// varying.993TEST_F(CollectVertexVariablesTest, ViewID_OVR)994{995const std::string &shaderString =996"#version 300 es\n"997"#extension GL_OVR_multiview2 : require\n"998"precision mediump float;\n"999"void main()\n"1000"{\n"1001" gl_Position = vec4(0.0);\n"1002"}\n";10031004ShBuiltInResources resources = mTranslator->getResources();1005resources.OVR_multiview2 = 1;1006resources.MaxViewsOVR = 4;1007initTranslator(resources);10081009compile(shaderString, SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW |1010SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER);10111012// The internal ViewID_OVR varying is not exposed through the ShaderVars interface.1013const auto &varyings = mTranslator->getOutputVaryings();1014ASSERT_EQ(1u, varyings.size());1015const ShaderVariable *varying = &varyings[0];1016EXPECT_EQ("gl_Position", varying->name);1017}10181019// Test all the fields of gl_in can be collected correctly in a geometry shader.1020TEST_F(CollectGeometryVariablesTest, CollectGLInFields)1021{1022const std::string &shaderString =1023R"(#version 310 es1024#extension GL_EXT_geometry_shader : require10251026layout (points) in;1027layout (points, max_vertices = 2) out;10281029void main()1030{1031vec4 value = gl_in[0].gl_Position;1032vec4 value2 = gl_in[0].gl_Position;1033gl_Position = value + value2;1034EmitVertex();1035})";10361037compile(shaderString);10381039EXPECT_EQ(1u, mTranslator->getOutputVaryings().size());10401041const std::vector<ShaderVariable> &inVaryings = mTranslator->getInputVaryings();1042ASSERT_EQ(1u, inVaryings.size());10431044const ShaderVariable &glIn = inVaryings[0];1045EXPECT_EQ("gl_in", glIn.name);1046EXPECT_EQ("gl_PerVertex", glIn.structOrBlockName);1047EXPECT_TRUE(glIn.staticUse);1048EXPECT_TRUE(glIn.active);1049EXPECT_TRUE(glIn.isBuiltIn());10501051ASSERT_EQ(1u, glIn.fields.size());10521053const ShaderVariable &glPositionField = glIn.fields[0];1054EXPECT_EQ("gl_Position", glPositionField.name);1055EXPECT_FALSE(glPositionField.isArray());1056EXPECT_FALSE(glPositionField.isStruct());1057EXPECT_TRUE(glPositionField.staticUse);1058// Tracking for "active" not set up currently.1059// EXPECT_TRUE(glPositionField.active);1060EXPECT_TRUE(glPositionField.isBuiltIn());1061EXPECT_GLENUM_EQ(GL_HIGH_FLOAT, glPositionField.precision);1062EXPECT_GLENUM_EQ(GL_FLOAT_VEC4, glPositionField.type);1063}10641065// Test the collected array size of gl_in matches the input primitive declaration.1066TEST_F(CollectGeometryVariablesTest, GLInArraySize)1067{1068const std::array<std::string, 5> kInputPrimitives = {1069{"points", "lines", "lines_adjacency", "triangles", "triangles_adjacency"}};10701071const GLuint kArraySizeForInputPrimitives[] = {1u, 2u, 4u, 3u, 6u};10721073const std::string &functionBody =1074R"(void main()1075{1076gl_Position = gl_in[0].gl_Position;1077})";10781079for (size_t i = 0; i < kInputPrimitives.size(); ++i)1080{1081compileGeometryShaderWithInputPrimitive(kInputPrimitives[i], "", functionBody);10821083const std::vector<ShaderVariable> &inVaryings = mTranslator->getInputVaryings();1084ASSERT_EQ(1u, inVaryings.size());10851086const ShaderVariable &glIn = inVaryings[0];1087ASSERT_EQ("gl_in", glIn.name);1088EXPECT_EQ(kArraySizeForInputPrimitives[i], glIn.arraySizes[0]);1089}1090}10911092// Test collecting gl_PrimitiveIDIn in a geometry shader.1093TEST_F(CollectGeometryVariablesTest, CollectPrimitiveIDIn)1094{1095const std::string &shaderString =1096R"(#version 310 es1097#extension GL_EXT_geometry_shader : require1098layout (points) in;1099layout (points, max_vertices = 2) out;1100void main()1101{1102gl_Position = vec4(gl_PrimitiveIDIn);1103EmitVertex();1104})";11051106compile(shaderString);11071108EXPECT_EQ(1u, mTranslator->getOutputVaryings().size());11091110const std::vector<ShaderVariable> &inputVaryings = mTranslator->getInputVaryings();1111ASSERT_EQ(1u, inputVaryings.size());11121113const ShaderVariable &varying = inputVaryings[0];1114EXPECT_EQ("gl_PrimitiveIDIn", varying.name);1115EXPECT_FALSE(varying.isArray());1116EXPECT_FALSE(varying.isStruct());1117EXPECT_TRUE(varying.staticUse);1118EXPECT_TRUE(varying.active);1119EXPECT_TRUE(varying.isBuiltIn());1120EXPECT_GLENUM_EQ(GL_HIGH_INT, varying.precision);1121EXPECT_GLENUM_EQ(GL_INT, varying.type);1122}11231124// Test collecting gl_InvocationID in a geometry shader.1125TEST_F(CollectGeometryVariablesTest, CollectInvocationID)1126{1127const std::string &shaderString =1128R"(#version 310 es1129#extension GL_EXT_geometry_shader : require1130layout (points, invocations = 2) in;1131layout (points, max_vertices = 2) out;1132void main()1133{1134gl_Position = vec4(gl_InvocationID);1135EmitVertex();1136})";11371138compile(shaderString);11391140EXPECT_EQ(1u, mTranslator->getOutputVaryings().size());11411142const std::vector<ShaderVariable> &inputVaryings = mTranslator->getInputVaryings();1143ASSERT_EQ(1u, inputVaryings.size());11441145const ShaderVariable &varying = inputVaryings[0];1146EXPECT_EQ("gl_InvocationID", varying.name);1147EXPECT_FALSE(varying.isArray());1148EXPECT_FALSE(varying.isStruct());1149EXPECT_TRUE(varying.staticUse);1150EXPECT_TRUE(varying.active);1151EXPECT_TRUE(varying.isBuiltIn());1152EXPECT_GLENUM_EQ(GL_HIGH_INT, varying.precision);1153EXPECT_GLENUM_EQ(GL_INT, varying.type);1154}11551156// Test collecting gl_in in a geometry shader when gl_in is indexed by an expression.1157TEST_F(CollectGeometryVariablesTest, CollectGLInIndexedByExpression)1158{1159const std::string &shaderString =1160R"(#version 310 es1161#extension GL_EXT_geometry_shader : require1162layout (triangles, invocations = 2) in;1163layout (points, max_vertices = 2) out;1164void main()1165{1166gl_Position = gl_in[gl_InvocationID + 1].gl_Position;1167EmitVertex();1168})";11691170compile(shaderString);11711172EXPECT_EQ(1u, mTranslator->getOutputVaryings().size());11731174const std::vector<ShaderVariable> &inVaryings = mTranslator->getInputVaryings();1175ASSERT_EQ(2u, inVaryings.size());11761177bool foundGLIn = false;1178bool foundInvocationID = false;11791180for (const ShaderVariable &varying : inVaryings)1181{1182if (varying.name == "gl_in")1183{1184foundGLIn = true;1185EXPECT_TRUE(varying.isShaderIOBlock);1186EXPECT_EQ("gl_PerVertex", varying.structOrBlockName);1187}1188else if (varying.name == "gl_InvocationID")1189{1190foundInvocationID = true;1191}1192}11931194EXPECT_TRUE(foundGLIn);1195EXPECT_TRUE(foundInvocationID);1196}11971198// Test collecting gl_Position in a geometry shader.1199TEST_F(CollectGeometryVariablesTest, CollectPosition)1200{1201const std::string &shaderString =1202R"(#version 310 es1203#extension GL_EXT_geometry_shader : require1204layout (points) in;1205layout (points, max_vertices = 2) out;1206void main()1207{1208gl_Position = vec4(0.1, 0.2, 0.3, 1);1209})";12101211compile(shaderString);12121213ASSERT_TRUE(mTranslator->getInputVaryings().empty());12141215const std::vector<ShaderVariable> &outputVaryings = mTranslator->getOutputVaryings();1216ASSERT_EQ(1u, outputVaryings.size());12171218const ShaderVariable &varying = outputVaryings[0];1219EXPECT_EQ("gl_Position", varying.name);1220EXPECT_FALSE(varying.isArray());1221EXPECT_FALSE(varying.isStruct());1222EXPECT_TRUE(varying.staticUse);1223EXPECT_TRUE(varying.active);1224EXPECT_TRUE(varying.isBuiltIn());1225EXPECT_GLENUM_EQ(GL_HIGH_FLOAT, varying.precision);1226EXPECT_GLENUM_EQ(GL_FLOAT_VEC4, varying.type);1227}12281229// Test collecting gl_PrimitiveID in a geometry shader.1230TEST_F(CollectGeometryVariablesTest, CollectPrimitiveID)1231{1232const std::string &shaderString =1233R"(#version 310 es1234#extension GL_EXT_geometry_shader : require1235layout (points) in;1236layout (points, max_vertices = 2) out;1237void main()1238{1239gl_PrimitiveID = 100;1240})";12411242compile(shaderString);12431244ASSERT_TRUE(mTranslator->getInputVaryings().empty());12451246const std::vector<ShaderVariable> &outputVaryings = mTranslator->getOutputVaryings();1247ASSERT_EQ(1u, outputVaryings.size());12481249const ShaderVariable &varying = outputVaryings[0];1250EXPECT_EQ("gl_PrimitiveID", varying.name);1251EXPECT_FALSE(varying.isArray());1252EXPECT_FALSE(varying.isStruct());1253EXPECT_TRUE(varying.staticUse);1254EXPECT_TRUE(varying.active);1255EXPECT_TRUE(varying.isBuiltIn());1256EXPECT_GLENUM_EQ(GL_HIGH_INT, varying.precision);1257EXPECT_GLENUM_EQ(GL_INT, varying.type);1258}12591260// Test collecting gl_Layer in a geometry shader.1261TEST_F(CollectGeometryVariablesTest, CollectLayer)1262{1263const std::string &shaderString =1264R"(#version 310 es1265#extension GL_EXT_geometry_shader : require1266layout (points) in;1267layout (points, max_vertices = 2) out;1268void main()1269{1270gl_Layer = 2;1271})";12721273compile(shaderString);12741275ASSERT_TRUE(mTranslator->getInputVaryings().empty());12761277const auto &outputVaryings = mTranslator->getOutputVaryings();1278ASSERT_EQ(1u, outputVaryings.size());12791280const ShaderVariable &varying = outputVaryings[0];1281EXPECT_EQ("gl_Layer", varying.name);1282EXPECT_FALSE(varying.isArray());1283EXPECT_FALSE(varying.isStruct());1284EXPECT_TRUE(varying.staticUse);1285EXPECT_TRUE(varying.active);1286EXPECT_TRUE(varying.isBuiltIn());1287EXPECT_GLENUM_EQ(GL_HIGH_INT, varying.precision);1288EXPECT_GLENUM_EQ(GL_INT, varying.type);1289}12901291// Test collecting gl_PrimitiveID in a fragment shader.1292TEST_F(CollectFragmentVariablesEXTGeometryShaderTest, CollectPrimitiveID)1293{1294const std::string &shaderString =1295R"(#version 310 es1296#extension GL_EXT_geometry_shader : require12971298out int my_out;12991300void main()1301{1302my_out = gl_PrimitiveID;1303})";13041305compile(shaderString);13061307ASSERT_TRUE(mTranslator->getOutputVaryings().empty());13081309const auto &inputVaryings = mTranslator->getInputVaryings();1310ASSERT_EQ(1u, inputVaryings.size());13111312const ShaderVariable *varying = &inputVaryings[0];1313EXPECT_EQ("gl_PrimitiveID", varying->name);1314EXPECT_FALSE(varying->isArray());1315EXPECT_FALSE(varying->isStruct());1316EXPECT_TRUE(varying->staticUse);1317EXPECT_TRUE(varying->active);1318EXPECT_TRUE(varying->isBuiltIn());1319EXPECT_GLENUM_EQ(GL_HIGH_INT, varying->precision);1320EXPECT_GLENUM_EQ(GL_INT, varying->type);1321}13221323// Test collecting gl_Layer in a fragment shader.1324TEST_F(CollectFragmentVariablesEXTGeometryShaderTest, CollectLayer)1325{1326const std::string &shaderString =1327R"(#version 310 es1328#extension GL_EXT_geometry_shader : require13291330out int my_out;13311332void main()1333{1334my_out = gl_Layer;1335})";13361337compile(shaderString);13381339ASSERT_TRUE(mTranslator->getOutputVaryings().empty());13401341const auto &inputVaryings = mTranslator->getInputVaryings();1342ASSERT_EQ(1u, inputVaryings.size());13431344const ShaderVariable *varying = &inputVaryings[0];1345EXPECT_EQ("gl_Layer", varying->name);1346EXPECT_FALSE(varying->isArray());1347EXPECT_FALSE(varying->isStruct());1348EXPECT_TRUE(varying->staticUse);1349EXPECT_TRUE(varying->active);1350EXPECT_TRUE(varying->isBuiltIn());1351EXPECT_GLENUM_EQ(GL_HIGH_INT, varying->precision);1352EXPECT_GLENUM_EQ(GL_INT, varying->type);1353}13541355// Test collecting the location of vertex shader outputs.1356TEST_F(CollectVertexVariablesES31Test, CollectOutputWithLocation)1357{1358const std::string &shaderString =1359R"(#version 310 es1360out vec4 v_output1;1361layout (location = 1) out vec4 v_output2;1362void main()1363{1364})";13651366compile(shaderString);13671368const auto &outputVaryings = mTranslator->getOutputVaryings();1369ASSERT_EQ(2u, outputVaryings.size());13701371const ShaderVariable *varying1 = &outputVaryings[0];1372EXPECT_EQ("v_output1", varying1->name);1373EXPECT_EQ(-1, varying1->location);13741375const ShaderVariable *varying2 = &outputVaryings[1];1376EXPECT_EQ("v_output2", varying2->name);1377EXPECT_EQ(1, varying2->location);1378}13791380// Test collecting the location of fragment shader inputs.1381TEST_F(CollectFragmentVariablesES31Test, CollectInputWithLocation)1382{1383const std::string &shaderString =1384R"(#version 310 es1385precision mediump float;1386in vec4 f_input1;1387layout (location = 1) in vec4 f_input2;1388layout (location = 0) out vec4 o_color;1389void main()1390{1391o_color = f_input2;1392})";13931394compile(shaderString);13951396const auto &inputVaryings = mTranslator->getInputVaryings();1397ASSERT_EQ(2u, inputVaryings.size());13981399const ShaderVariable *varying1 = &inputVaryings[0];1400EXPECT_EQ("f_input1", varying1->name);1401EXPECT_EQ(-1, varying1->location);14021403const ShaderVariable *varying2 = &inputVaryings[1];1404EXPECT_EQ("f_input2", varying2->name);1405EXPECT_EQ(1, varying2->location);1406}14071408// Test collecting the inputs of a geometry shader.1409TEST_F(CollectGeometryVariablesTest, CollectInputs)1410{1411const std::string &shaderString =1412R"(#version 310 es1413#extension GL_EXT_geometry_shader : require1414layout (points) in;1415layout (points, max_vertices = 2) out;1416in vec4 texcoord1[];1417in vec4 texcoord2[1];1418void main()1419{1420gl_Position = texcoord1[0];1421gl_Position += texcoord2[0];1422EmitVertex();1423})";14241425compile(shaderString);14261427EXPECT_EQ(1u, mTranslator->getOutputVaryings().size());14281429const auto &inputVaryings = mTranslator->getInputVaryings();1430ASSERT_EQ(2u, inputVaryings.size());14311432const std::string kVaryingName[] = {"texcoord1", "texcoord2"};14331434for (size_t i = 0; i < inputVaryings.size(); ++i)1435{1436const ShaderVariable &varying = inputVaryings[i];14371438EXPECT_EQ(kVaryingName[i], varying.name);1439EXPECT_TRUE(varying.isArray());1440EXPECT_FALSE(varying.isStruct());1441EXPECT_TRUE(varying.staticUse);1442EXPECT_TRUE(varying.active);1443EXPECT_FALSE(varying.isBuiltIn());1444EXPECT_GLENUM_EQ(GL_HIGH_FLOAT, varying.precision);1445EXPECT_GLENUM_EQ(GL_FLOAT_VEC4, varying.type);1446EXPECT_FALSE(varying.isInvariant);1447ASSERT_EQ(1u, varying.arraySizes.size());1448EXPECT_EQ(1u, varying.arraySizes.back());1449}1450}14511452// Test that the unsized input of a geometry shader can be correctly collected.1453TEST_F(CollectGeometryVariablesTest, CollectInputArraySizeForUnsizedInput)1454{1455const std::array<std::string, 5> kInputPrimitives = {1456{"points", "lines", "lines_adjacency", "triangles", "triangles_adjacency"}};14571458const GLuint kArraySizeForInputPrimitives[] = {1u, 2u, 4u, 3u, 6u};14591460const std::string &kVariableDeclaration = "in vec4 texcoord[];\n";1461const std::string &kFunctionBody =1462R"(void main()1463{1464gl_Position = texcoord[0];1465})";14661467for (size_t i = 0; i < kInputPrimitives.size(); ++i)1468{1469compileGeometryShaderWithInputPrimitive(kInputPrimitives[i], kVariableDeclaration,1470kFunctionBody);14711472const auto &inputVaryings = mTranslator->getInputVaryings();1473ASSERT_EQ(1u, inputVaryings.size());14741475const ShaderVariable *varying = &inputVaryings[0];1476EXPECT_EQ("texcoord", varying->name);1477ASSERT_EQ(1u, varying->arraySizes.size());1478EXPECT_EQ(kArraySizeForInputPrimitives[i], varying->arraySizes.back());1479}1480}14811482// Test collecting inputs using interpolation qualifiers in a geometry shader.1483TEST_F(CollectGeometryVariablesTest, CollectInputsWithInterpolationQualifiers)1484{1485const std::string &kHeader =1486"#version 310 es\n"1487"#extension GL_EXT_geometry_shader : require\n";1488const std::string &kLayout =1489"layout (points) in;\n"1490"layout (points, max_vertices = 2) out;\n";14911492const std::array<std::string, 3> kInterpolationQualifiers = {{"flat", "smooth", "centroid"}};14931494const std::array<InterpolationType, 3> kInterpolationType = {1495{INTERPOLATION_FLAT, INTERPOLATION_SMOOTH, INTERPOLATION_CENTROID}};14961497const std::string &kFunctionBody =1498R"(void main()1499{1500gl_Position = texcoord[0];1501EmitVertex();1502})";15031504for (size_t i = 0; i < kInterpolationQualifiers.size(); ++i)1505{1506const std::string &qualifier = kInterpolationQualifiers[i];15071508std::ostringstream stream1;1509stream1 << kHeader << kLayout << qualifier << " in vec4 texcoord[];\n" << kFunctionBody;1510compile(stream1.str());15111512const auto &inputVaryings = mTranslator->getInputVaryings();1513ASSERT_EQ(1u, inputVaryings.size());1514const ShaderVariable *varying = &inputVaryings[0];1515EXPECT_EQ("texcoord", varying->name);1516EXPECT_EQ(kInterpolationType[i], varying->interpolation);1517}1518}15191520// Test collecting outputs using interpolation qualifiers in a geometry shader.1521TEST_F(CollectGeometryVariablesTest, CollectOutputsWithInterpolationQualifiers)1522{1523const std::string &kHeader =1524"#version 310 es\n"1525"#extension GL_EXT_geometry_shader : require\n"1526"layout (points) in;\n"1527"layout (points, max_vertices = 2) out;\n";15281529const std::array<std::string, 4> kInterpolationQualifiers = {1530{"", "flat", "smooth", "centroid"}};15311532const std::array<InterpolationType, 4> kInterpolationType = {1533{INTERPOLATION_SMOOTH, INTERPOLATION_FLAT, INTERPOLATION_SMOOTH, INTERPOLATION_CENTROID}};15341535const std::string &kFunctionBody =1536"void main()\n"1537"{\n"1538" texcoord = vec4(1.0, 0.0, 0.0, 1.0);\n"1539"}\n";15401541for (size_t i = 0; i < kInterpolationQualifiers.size(); ++i)1542{1543const std::string &qualifier = kInterpolationQualifiers[i];1544std::ostringstream stream;1545stream << kHeader << qualifier << " out vec4 texcoord;\n" << kFunctionBody;15461547compile(stream.str());1548const auto &outputVaryings = mTranslator->getOutputVaryings();1549ASSERT_EQ(1u, outputVaryings.size());15501551const ShaderVariable *varying = &outputVaryings[0];1552EXPECT_EQ("texcoord", varying->name);1553EXPECT_EQ(kInterpolationType[i], varying->interpolation);1554EXPECT_FALSE(varying->isInvariant);1555}1556}15571558// Test collecting outputs using 'invariant' qualifier in a geometry shader.1559TEST_F(CollectGeometryVariablesTest, CollectOutputsWithInvariant)1560{1561const std::string &shaderString =1562R"(#version 310 es1563#extension GL_EXT_geometry_shader : require1564layout (points) in;1565layout (points, max_vertices = 2) out;1566invariant out vec4 texcoord;1567void main()1568{1569texcoord = vec4(1.0, 0.0, 0.0, 1.0);1570})";15711572compile(shaderString);15731574const auto &outputVaryings = mTranslator->getOutputVaryings();1575ASSERT_EQ(1u, outputVaryings.size());15761577const ShaderVariable *varying = &outputVaryings[0];1578EXPECT_EQ("texcoord", varying->name);1579EXPECT_TRUE(varying->isInvariant);1580}15811582// Test collecting a varying variable that is used inside a folded ternary operator. The result of1583// the folded ternary operator has a different qualifier from the original variable, which makes1584// this case tricky.1585TEST_F(CollectFragmentVariablesTest, VaryingUsedInsideFoldedTernary)1586{1587const std::string &shaderString =1588R"(#version 300 es1589precision highp float;1590centroid in float vary;1591out vec4 color;1592void main() {1593color = vec4(0.0, true ? vary : 0.0, 0.0, 1.0);1594})";15951596compile(shaderString);15971598const std::vector<ShaderVariable> &varyings = mTranslator->getInputVaryings();1599ASSERT_EQ(1u, varyings.size());16001601const ShaderVariable *varying = &varyings[0];16021603EXPECT_FALSE(varying->isArray());1604EXPECT_GLENUM_EQ(GL_HIGH_FLOAT, varying->precision);1605EXPECT_TRUE(varying->staticUse);1606EXPECT_TRUE(varying->active);1607EXPECT_GLENUM_EQ(GL_FLOAT, varying->type);1608EXPECT_EQ("vary", varying->name);1609EXPECT_EQ(DecorateName("vary"), varying->mappedName);1610EXPECT_EQ(INTERPOLATION_CENTROID, varying->interpolation);1611}16121613// Test a variable that is statically used but not active. The variable is used in a branch of a1614// ternary op that is not evaluated.1615TEST_F(CollectFragmentVariablesTest, StaticallyUsedButNotActiveInTernaryOp)1616{1617const std::string &shaderString =1618R"(#version 300 es1619precision mediump float;1620out vec4 out_fragColor;1621uniform float u;1622void main()1623{1624out_fragColor = vec4(true ? 0.0 : u);1625})";16261627compile(shaderString);1628checkUniformStaticallyUsedButNotActive("u");1629}16301631// Test a variable that is statically used but not active. The variable is a return value in an1632// unused function.1633TEST_F(CollectFragmentVariablesTest, StaticallyUsedButNotActiveAsReturnValue)1634{1635const std::string &shaderString =1636R"(#version 300 es1637precision mediump float;1638out vec4 out_fragColor;1639uniform float u;1640float f() {1641return u;1642}1643void main()1644{1645out_fragColor = vec4(0.0);1646})";16471648compile(shaderString);1649checkUniformStaticallyUsedButNotActive("u");1650}16511652// Test a variable that is statically used but not active. The variable is an if statement condition1653// inside a block that is not executed.1654TEST_F(CollectFragmentVariablesTest, StaticallyUsedButNotActiveAsIfCondition)1655{1656const std::string &shaderString =1657R"(#version 300 es1658precision mediump float;1659out vec4 out_fragColor;1660uniform bool u;1661void main()1662{1663if (false) {1664if (u) {1665out_fragColor = vec4(1.0);1666}1667}1668out_fragColor = vec4(0.0);1669})";16701671compile(shaderString);1672checkUniformStaticallyUsedButNotActive("u");1673}16741675// Test a variable that is statically used but not active. The variable is a constructor argument in1676// a block that is not executed.1677TEST_F(CollectFragmentVariablesTest, StaticallyUsedButNotActiveAsConstructorArgument)1678{1679const std::string &shaderString =1680R"(#version 300 es1681precision mediump float;1682out vec4 out_fragColor;1683uniform float u;1684void main()1685{1686if (false) {1687out_fragColor = vec4(u);1688}1689out_fragColor = vec4(0.0);1690})";16911692compile(shaderString);1693checkUniformStaticallyUsedButNotActive("u");1694}16951696// Test a variable that is statically used but not active. The variable is a binary operator operand1697// in a block that is not executed.1698TEST_F(CollectFragmentVariablesTest, StaticallyUsedButNotActiveAsBinaryOpOperand)1699{1700const std::string &shaderString =1701R"(#version 300 es1702precision mediump float;1703out vec4 out_fragColor;1704uniform vec4 u;1705void main()1706{1707if (false) {1708out_fragColor = u + 1.0;1709}1710out_fragColor = vec4(0.0);1711})";17121713compile(shaderString);1714checkUniformStaticallyUsedButNotActive("u");1715}17161717// Test a variable that is statically used but not active. The variable is a comparison operator1718// operand in a block that is not executed.1719TEST_F(CollectFragmentVariablesTest, StaticallyUsedButNotActiveAsComparisonOpOperand)1720{1721const std::string &shaderString =1722R"(#version 300 es1723precision mediump float;1724out vec4 out_fragColor;1725uniform vec4 u;1726void main()1727{1728if (false) {1729if (u == vec4(1.0))1730{1731out_fragColor = vec4(1.0);1732}1733}1734out_fragColor = vec4(0.0);1735})";17361737compile(shaderString);1738checkUniformStaticallyUsedButNotActive("u");1739}17401741// Test a variable that is statically used but not active. The variable is an unary operator operand1742// in a block that is not executed.1743TEST_F(CollectFragmentVariablesTest, StaticallyUsedButNotActiveAsUnaryOpOperand)1744{1745const std::string &shaderString =1746R"(#version 300 es1747precision mediump float;1748out vec4 out_fragColor;1749uniform vec4 u;1750void main()1751{1752if (false) {1753out_fragColor = -u;1754}1755out_fragColor = vec4(0.0);1756})";17571758compile(shaderString);1759checkUniformStaticallyUsedButNotActive("u");1760}17611762// Test a variable that is statically used but not active. The variable is an rvalue in an assigment1763// in a block that is not executed.1764TEST_F(CollectFragmentVariablesTest, StaticallyUsedButNotActiveAsAssignmentRValue)1765{1766const std::string &shaderString =1767R"(#version 300 es1768precision mediump float;1769out vec4 out_fragColor;1770uniform vec4 u;1771void main()1772{1773if (false) {1774out_fragColor = u;1775}1776out_fragColor = vec4(0.0);1777})";17781779compile(shaderString);1780checkUniformStaticallyUsedButNotActive("u");1781}17821783// Test a variable that is statically used but not active. The variable is a comma operator operand1784// in a block that is not executed.1785TEST_F(CollectFragmentVariablesTest, StaticallyUsedButNotActiveAsCommaOperand)1786{1787const std::string &shaderString =1788R"(#version 300 es1789precision mediump float;1790out vec4 out_fragColor;1791uniform vec4 u;1792void main()1793{1794if (false) {1795out_fragColor = u, vec4(1.0);1796}1797out_fragColor = vec4(0.0);1798})";17991800compile(shaderString);1801checkUniformStaticallyUsedButNotActive("u");1802}18031804// Test a variable that is statically used but not active. The variable is a switch init statement1805// in a block that is not executed.1806TEST_F(CollectFragmentVariablesTest, StaticallyUsedButNotActiveAsSwitchInitStatement)1807{1808const std::string &shaderString =1809R"(#version 300 es1810precision mediump float;1811out vec4 out_fragColor;1812uniform int u;1813void main()1814{1815if (false)1816{1817switch (u)1818{1819case 1:1820out_fragColor = vec4(2.0);1821default:1822out_fragColor = vec4(1.0);1823}1824}1825out_fragColor = vec4(0.0);1826})";18271828compile(shaderString);1829checkUniformStaticallyUsedButNotActive("u");1830}18311832// Test a variable that is statically used but not active. The variable is a loop condition in a1833// block that is not executed.1834TEST_F(CollectFragmentVariablesTest, StaticallyUsedButNotActiveAsLoopCondition)1835{1836const std::string &shaderString =1837R"(#version 300 es1838precision mediump float;1839out vec4 out_fragColor;1840uniform bool u;1841void main()1842{1843int counter = 0;1844if (false)1845{1846while (u)1847{1848if (++counter > 2)1849{1850break;1851}1852}1853}1854out_fragColor = vec4(0.0);1855})";18561857compile(shaderString);1858checkUniformStaticallyUsedButNotActive("u");1859}18601861// Test a variable that is statically used but not active. The variable is a loop expression in a1862// block that is not executed.1863TEST_F(CollectFragmentVariablesTest, StaticallyUsedButNotActiveAsLoopExpression)1864{1865const std::string &shaderString =1866R"(#version 300 es1867precision mediump float;1868out vec4 out_fragColor;1869uniform bool u;1870void main()1871{1872if (false)1873{1874for (int i = 0; i < 3; u)1875{1876++i;1877}1878}1879out_fragColor = vec4(0.0);1880})";18811882compile(shaderString);1883checkUniformStaticallyUsedButNotActive("u");1884}18851886// Test a variable that is statically used but not active. The variable is a vector index in a block1887// that is not executed.1888TEST_F(CollectFragmentVariablesTest, StaticallyUsedButNotActiveAsVectorIndex)1889{1890const std::string &shaderString =1891R"(#version 300 es1892precision mediump float;1893out vec4 out_fragColor;1894uniform int u;1895void main()1896{1897vec4 color = vec4(0.0);1898if (false)1899{1900color[u] = 1.0;1901}1902out_fragColor = color;1903})";19041905compile(shaderString);1906checkUniformStaticallyUsedButNotActive("u");1907}19081909// Test a variable that is statically used but not active. The variable is referenced in a block1910// that's not executed. This is a bit of a corner case with some room for interpretation, but we1911// treat the variable as statically used.1912TEST_F(CollectFragmentVariablesTest, StaticallyUsedButNotActiveJustAReference)1913{1914const std::string &shaderString =1915R"(#version 300 es1916precision mediump float;1917out vec4 out_fragColor;1918uniform int u;1919void main()1920{1921vec4 color = vec4(0.0);1922if (false)1923{1924u;1925}1926out_fragColor = color;1927})";19281929compile(shaderString);1930checkUniformStaticallyUsedButNotActive("u");1931}19321933// Test a variable that is statically used but not active. The variable is referenced in a block1934// without braces that's not executed. This is a bit of a corner case with some room for1935// interpretation, but we treat the variable as statically used.1936TEST_F(CollectFragmentVariablesTest, StaticallyUsedButNotActiveJustAReferenceNoBracesIf)1937{1938const std::string &shaderString =1939R"(#version 300 es1940precision mediump float;1941out vec4 out_fragColor;1942uniform int u;1943void main()1944{1945vec4 color = vec4(0.0);1946if (false)1947u;1948out_fragColor = color;1949})";19501951compile(shaderString);1952checkUniformStaticallyUsedButNotActive("u");1953}19541955// Test a variable that is referenced in a loop body without braces.1956TEST_F(CollectFragmentVariablesTest, JustAVariableReferenceInNoBracesLoop)1957{1958const std::string &shaderString =1959R"(#version 300 es1960precision mediump float;1961out vec4 out_fragColor;1962uniform int u;1963void main()1964{1965vec4 color = vec4(0.0);1966while (false)1967u;1968out_fragColor = color;1969})";19701971compile(shaderString);19721973const auto &uniforms = mTranslator->getUniforms();1974ASSERT_EQ(1u, uniforms.size());19751976const ShaderVariable &uniform = uniforms[0];1977EXPECT_EQ("u", uniform.name);1978EXPECT_TRUE(uniform.staticUse);1979// Note that we don't check the active flag here - the usage of the uniform is not currently1980// being optimized away.1981}19821983// Test an interface block member variable that is statically used but not active.1984TEST_F(CollectVertexVariablesTest, StaticallyUsedButNotActiveSimpleInterfaceBlock)1985{1986const std::string &shaderString =1987R"(#version 300 es1988uniform b1989{1990float f;1991};1992void main() {1993gl_Position = vec4(true ? 0.0 : f);1994})";19951996compile(shaderString);19971998const std::vector<InterfaceBlock> &interfaceBlocks = mTranslator->getInterfaceBlocks();1999ASSERT_EQ(1u, interfaceBlocks.size());2000const InterfaceBlock &interfaceBlock = interfaceBlocks[0];20012002EXPECT_EQ("b", interfaceBlock.name);2003EXPECT_TRUE(interfaceBlock.staticUse);2004EXPECT_FALSE(interfaceBlock.active);20052006ASSERT_EQ(1u, interfaceBlock.fields.size());2007const ShaderVariable &field = interfaceBlock.fields[0];20082009EXPECT_EQ("f", field.name);2010EXPECT_TRUE(field.staticUse);2011EXPECT_FALSE(field.active);2012}20132014// Test an interface block instance variable that is statically used but not active.2015TEST_F(CollectVertexVariablesTest, StaticallyUsedButNotActiveInstancedInterfaceBlock)2016{2017const std::string &shaderString =2018R"(#version 300 es2019uniform b2020{2021float f;2022} blockInstance;2023void main() {2024gl_Position = vec4(true ? 0.0 : blockInstance.f);2025})";20262027compile(shaderString);20282029const std::vector<InterfaceBlock> &interfaceBlocks = mTranslator->getInterfaceBlocks();2030ASSERT_EQ(1u, interfaceBlocks.size());2031const InterfaceBlock &interfaceBlock = interfaceBlocks[0];20322033EXPECT_EQ("b", interfaceBlock.name);2034EXPECT_TRUE(interfaceBlock.staticUse);2035EXPECT_FALSE(interfaceBlock.active);20362037ASSERT_EQ(1u, interfaceBlock.fields.size());2038const ShaderVariable &field = interfaceBlock.fields[0];20392040EXPECT_EQ("f", field.name);2041// See TODO in CollectVariables.cpp about tracking instanced interface block field static use.2042// EXPECT_TRUE(field.staticUse);2043EXPECT_FALSE(field.active);2044}20452046// Test an interface block member variable that is statically used. The variable is used to call2047// array length method.2048TEST_F(CollectVertexVariablesTest, StaticallyUsedInArrayLengthOp)2049{2050const std::string &shaderString =2051R"(#version 300 es2052uniform b2053{2054float f[3];2055};2056void main() {2057if (f.length() > 1)2058{2059gl_Position = vec4(1.0);2060}2061else2062{2063gl_Position = vec4(0.0);2064}2065})";20662067compile(shaderString);20682069const std::vector<InterfaceBlock> &interfaceBlocks = mTranslator->getInterfaceBlocks();2070ASSERT_EQ(1u, interfaceBlocks.size());2071const InterfaceBlock &interfaceBlock = interfaceBlocks[0];20722073EXPECT_EQ("b", interfaceBlock.name);2074EXPECT_TRUE(interfaceBlock.staticUse);2075}20762077// Test a varying that is declared invariant but not otherwise used.2078TEST_F(CollectVertexVariablesTest, VaryingOnlyDeclaredInvariant)2079{2080const std::string &shaderString =2081R"(precision mediump float;2082varying float vf;2083invariant vf;2084void main()2085{2086})";20872088compile(shaderString);20892090const auto &varyings = mTranslator->getOutputVaryings();2091ASSERT_EQ(1u, varyings.size());20922093const ShaderVariable &varying = varyings[0];2094EXPECT_EQ("vf", varying.name);2095EXPECT_FALSE(varying.staticUse);2096EXPECT_FALSE(varying.active);2097}20982099// Test an output variable that is declared with the index layout qualifier from2100// EXT_blend_func_extended.2101TEST_F(CollectFragmentVariablesTest, OutputVarESSL3EXTBlendFuncExtendedIndex)2102{2103const std::string &shaderString =2104R"(#version 300 es2105#extension GL_EXT_blend_func_extended : require2106precision mediump float;2107layout(location = 0, index = 1) out float outVar;2108void main()2109{2110outVar = 0.0;2111})";21122113compile(shaderString);21142115const auto &outputs = mTranslator->getOutputVariables();2116ASSERT_EQ(1u, outputs.size());21172118const ShaderVariable &output = outputs[0];2119EXPECT_EQ("outVar", output.name);2120EXPECT_TRUE(output.staticUse);2121EXPECT_TRUE(output.active);2122EXPECT_EQ(1, output.index);2123}212421252126