Path: blob/main_old/src/compiler/translator/CollectVariables.cpp
1693 views
//1// Copyright 2002 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.cpp: Collect lists of shader interface variables based on the AST.67#include "compiler/translator/CollectVariables.h"89#include "angle_gl.h"10#include "common/utilities.h"11#include "compiler/translator/HashNames.h"12#include "compiler/translator/SymbolTable.h"13#include "compiler/translator/tree_util/IntermTraverse.h"14#include "compiler/translator/util.h"1516namespace sh17{1819namespace20{2122BlockLayoutType GetBlockLayoutType(TLayoutBlockStorage blockStorage)23{24switch (blockStorage)25{26case EbsPacked:27return BLOCKLAYOUT_PACKED;28case EbsShared:29return BLOCKLAYOUT_SHARED;30case EbsStd140:31return BLOCKLAYOUT_STD140;32case EbsStd430:33return BLOCKLAYOUT_STD430;34default:35UNREACHABLE();36return BLOCKLAYOUT_SHARED;37}38}3940BlockType GetBlockType(TQualifier qualifier)41{42switch (qualifier)43{44case EvqUniform:45return BlockType::BLOCK_UNIFORM;46case EvqBuffer:47return BlockType::BLOCK_BUFFER;48default:49UNREACHABLE();50return BlockType::BLOCK_UNIFORM;51}52}5354template <class VarT>55VarT *FindVariable(const ImmutableString &name, std::vector<VarT> *infoList)56{57// TODO(zmo): optimize this function.58for (size_t ii = 0; ii < infoList->size(); ++ii)59{60if (name == (*infoList)[ii].name)61return &((*infoList)[ii]);62}6364return nullptr;65}6667void MarkActive(ShaderVariable *variable)68{69if (!variable->active)70{71if (variable->isStruct())72{73// Conservatively assume all fields are statically used as well.74for (auto &field : variable->fields)75{76MarkActive(&field);77}78}79variable->staticUse = true;80variable->active = true;81}82}8384ShaderVariable *FindVariableInInterfaceBlock(const ImmutableString &name,85const TInterfaceBlock *interfaceBlock,86std::vector<InterfaceBlock> *infoList)87{88ASSERT(interfaceBlock);89InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), infoList);90ASSERT(namedBlock);9192// Set static use on the parent interface block here93namedBlock->staticUse = true;94namedBlock->active = true;95return FindVariable(name, &namedBlock->fields);96}9798ShaderVariable *FindShaderIOBlockVariable(const ImmutableString &blockName,99std::vector<ShaderVariable> *infoList)100{101for (size_t index = 0; index < infoList->size(); ++index)102{103if (blockName == (*infoList)[index].structOrBlockName)104return &(*infoList)[index];105}106107return nullptr;108}109110// Traverses the intermediate tree to collect all attributes, uniforms, varyings, fragment outputs,111// shared data and interface blocks.112class CollectVariablesTraverser : public TIntermTraverser113{114public:115CollectVariablesTraverser(std::vector<ShaderVariable> *attribs,116std::vector<ShaderVariable> *outputVariables,117std::vector<ShaderVariable> *uniforms,118std::vector<ShaderVariable> *inputVaryings,119std::vector<ShaderVariable> *outputVaryings,120std::vector<ShaderVariable> *sharedVariables,121std::vector<InterfaceBlock> *uniformBlocks,122std::vector<InterfaceBlock> *shaderStorageBlocks,123ShHashFunction64 hashFunction,124TSymbolTable *symbolTable,125GLenum shaderType,126const TExtensionBehavior &extensionBehavior,127const ShBuiltInResources &resources,128int tessControlShaderOutputVertices);129130bool visitGlobalQualifierDeclaration(Visit visit,131TIntermGlobalQualifierDeclaration *node) override;132void visitSymbol(TIntermSymbol *symbol) override;133bool visitDeclaration(Visit, TIntermDeclaration *node) override;134bool visitBinary(Visit visit, TIntermBinary *binaryNode) override;135136private:137std::string getMappedName(const TSymbol *symbol) const;138139void setFieldOrVariableProperties(const TType &type,140bool staticUse,141bool isShaderIOBlock,142bool isPatch,143ShaderVariable *variableOut) const;144void setFieldProperties(const TType &type,145const ImmutableString &name,146bool staticUse,147bool isShaderIOBlock,148bool isPatch,149ShaderVariable *variableOut) const;150void setCommonVariableProperties(const TType &type,151const TVariable &variable,152ShaderVariable *variableOut) const;153154ShaderVariable recordAttribute(const TIntermSymbol &variable) const;155ShaderVariable recordOutputVariable(const TIntermSymbol &variable) const;156ShaderVariable recordVarying(const TIntermSymbol &variable) const;157void recordInterfaceBlock(const char *instanceName,158const TType &interfaceBlockType,159InterfaceBlock *interfaceBlock) const;160ShaderVariable recordUniform(const TIntermSymbol &variable) const;161162void setBuiltInInfoFromSymbol(const TVariable &variable, ShaderVariable *info);163164void recordBuiltInVaryingUsed(const TVariable &variable,165bool *addedFlag,166std::vector<ShaderVariable> *varyings);167void recordBuiltInFragmentOutputUsed(const TVariable &variable, bool *addedFlag);168void recordBuiltInAttributeUsed(const TVariable &variable, bool *addedFlag);169InterfaceBlock *findNamedInterfaceBlock(const ImmutableString &name) const;170171std::vector<ShaderVariable> *mAttribs;172std::vector<ShaderVariable> *mOutputVariables;173std::vector<ShaderVariable> *mUniforms;174std::vector<ShaderVariable> *mInputVaryings;175std::vector<ShaderVariable> *mOutputVaryings;176std::vector<ShaderVariable> *mSharedVariables;177std::vector<InterfaceBlock> *mUniformBlocks;178std::vector<InterfaceBlock> *mShaderStorageBlocks;179180std::map<std::string, ShaderVariable *> mInterfaceBlockFields;181182// Shader uniforms183bool mDepthRangeAdded;184bool mNumSamplesAdded;185186// Compute Shader builtins187bool mNumWorkGroupsAdded;188bool mWorkGroupIDAdded;189bool mLocalInvocationIDAdded;190bool mGlobalInvocationIDAdded;191bool mLocalInvocationIndexAdded;192193// Vertex Shader builtins194bool mInstanceIDAdded;195bool mVertexIDAdded;196bool mPointSizeAdded;197bool mDrawIDAdded;198199// Vertex Shader and Geometry Shader builtins200bool mPositionAdded;201bool mClipDistanceAdded;202bool mCullDistanceAdded;203204// Fragment Shader builtins205bool mPointCoordAdded;206bool mFrontFacingAdded;207bool mHelperInvocationAdded;208bool mFragCoordAdded;209bool mLastFragDataAdded;210bool mFragColorAdded;211bool mFragDataAdded;212bool mFragDepthAdded;213bool mSecondaryFragColorEXTAdded;214bool mSecondaryFragDataEXTAdded;215bool mSampleIDAdded;216bool mSamplePositionAdded;217bool mSampleMaskAdded;218bool mSampleMaskInAdded;219220// Geometry and Tessellation Shader builtins221bool mPerVertexInAdded;222bool mPerVertexOutAdded;223224// Geometry Shader builtins225bool mPrimitiveIDInAdded;226bool mInvocationIDAdded;227228// Geometry Shader and Fragment Shader builtins229bool mPrimitiveIDAdded;230bool mLayerAdded;231232// Shared memory variables233bool mSharedVariableAdded;234235// Tessellation Shader builtins236bool mPatchVerticesInAdded;237bool mTessLevelOuterAdded;238bool mTessLevelInnerAdded;239bool mBoundingBoxEXTAdded;240bool mTessCoordAdded;241const int mTessControlShaderOutputVertices;242243ShHashFunction64 mHashFunction;244245GLenum mShaderType;246const TExtensionBehavior &mExtensionBehavior;247const ShBuiltInResources &mResources;248};249250CollectVariablesTraverser::CollectVariablesTraverser(251std::vector<sh::ShaderVariable> *attribs,252std::vector<sh::ShaderVariable> *outputVariables,253std::vector<sh::ShaderVariable> *uniforms,254std::vector<sh::ShaderVariable> *inputVaryings,255std::vector<sh::ShaderVariable> *outputVaryings,256std::vector<sh::ShaderVariable> *sharedVariables,257std::vector<sh::InterfaceBlock> *uniformBlocks,258std::vector<sh::InterfaceBlock> *shaderStorageBlocks,259ShHashFunction64 hashFunction,260TSymbolTable *symbolTable,261GLenum shaderType,262const TExtensionBehavior &extensionBehavior,263const ShBuiltInResources &resources,264int tessControlShaderOutputVertices)265: TIntermTraverser(true, false, false, symbolTable),266mAttribs(attribs),267mOutputVariables(outputVariables),268mUniforms(uniforms),269mInputVaryings(inputVaryings),270mOutputVaryings(outputVaryings),271mSharedVariables(sharedVariables),272mUniformBlocks(uniformBlocks),273mShaderStorageBlocks(shaderStorageBlocks),274mDepthRangeAdded(false),275mNumSamplesAdded(false),276mNumWorkGroupsAdded(false),277mWorkGroupIDAdded(false),278mLocalInvocationIDAdded(false),279mGlobalInvocationIDAdded(false),280mLocalInvocationIndexAdded(false),281mInstanceIDAdded(false),282mVertexIDAdded(false),283mPointSizeAdded(false),284mDrawIDAdded(false),285mPositionAdded(false),286mClipDistanceAdded(false),287mCullDistanceAdded(false),288mPointCoordAdded(false),289mFrontFacingAdded(false),290mHelperInvocationAdded(false),291mFragCoordAdded(false),292mLastFragDataAdded(false),293mFragColorAdded(false),294mFragDataAdded(false),295mFragDepthAdded(false),296mSecondaryFragColorEXTAdded(false),297mSecondaryFragDataEXTAdded(false),298mSampleIDAdded(false),299mSamplePositionAdded(false),300mSampleMaskAdded(false),301mSampleMaskInAdded(false),302mPerVertexInAdded(false),303mPerVertexOutAdded(false),304mPrimitiveIDInAdded(false),305mInvocationIDAdded(false),306mPrimitiveIDAdded(false),307mLayerAdded(false),308mSharedVariableAdded(false),309mPatchVerticesInAdded(false),310mTessLevelOuterAdded(false),311mTessLevelInnerAdded(false),312mBoundingBoxEXTAdded(false),313mTessCoordAdded(false),314mTessControlShaderOutputVertices(tessControlShaderOutputVertices),315mHashFunction(hashFunction),316mShaderType(shaderType),317mExtensionBehavior(extensionBehavior),318mResources(resources)319{}320321std::string CollectVariablesTraverser::getMappedName(const TSymbol *symbol) const322{323return HashName(symbol, mHashFunction, nullptr).data();324}325326void CollectVariablesTraverser::setBuiltInInfoFromSymbol(const TVariable &variable,327ShaderVariable *info)328{329const TType &type = variable.getType();330331info->name = variable.name().data();332info->mappedName = variable.name().data();333334bool isShaderIOBlock =335IsShaderIoBlock(type.getQualifier()) && type.getInterfaceBlock() != nullptr;336bool isPatch = type.getQualifier() == EvqTessLevelInner ||337type.getQualifier() == EvqTessLevelOuter ||338type.getQualifier() == EvqBoundingBoxEXT;339340setFieldOrVariableProperties(type, true, isShaderIOBlock, isPatch, info);341}342343void CollectVariablesTraverser::recordBuiltInVaryingUsed(const TVariable &variable,344bool *addedFlag,345std::vector<ShaderVariable> *varyings)346{347ASSERT(varyings);348if (!(*addedFlag))349{350ShaderVariable info;351setBuiltInInfoFromSymbol(variable, &info);352info.active = true;353info.isInvariant = mSymbolTable->isVaryingInvariant(variable);354355varyings->push_back(info);356(*addedFlag) = true;357}358}359360void CollectVariablesTraverser::recordBuiltInFragmentOutputUsed(const TVariable &variable,361bool *addedFlag)362{363if (!(*addedFlag))364{365ShaderVariable info;366setBuiltInInfoFromSymbol(variable, &info);367info.active = true;368mOutputVariables->push_back(info);369(*addedFlag) = true;370}371}372373void CollectVariablesTraverser::recordBuiltInAttributeUsed(const TVariable &variable,374bool *addedFlag)375{376if (!(*addedFlag))377{378ShaderVariable info;379setBuiltInInfoFromSymbol(variable, &info);380info.active = true;381info.location = -1;382mAttribs->push_back(info);383(*addedFlag) = true;384}385}386387bool CollectVariablesTraverser::visitGlobalQualifierDeclaration(388Visit visit,389TIntermGlobalQualifierDeclaration *node)390{391// We should not mark variables as active just based on an invariant/precise declaration, so we392// don't traverse the symbols declared invariant.393return false;394}395396// We want to check whether a uniform/varying is active because we need to skip updating inactive397// ones. We also only count the active ones in packing computing. Also, gl_FragCoord, gl_PointCoord,398// and gl_FrontFacing count toward varying counting if they are active in a fragment shader.399void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol)400{401ASSERT(symbol != nullptr);402403if (symbol->variable().symbolType() == SymbolType::AngleInternal ||404symbol->variable().symbolType() == SymbolType::Empty)405{406// Internal variables or nameless variables are not collected.407return;408}409410ShaderVariable *var = nullptr;411412const ImmutableString &symbolName = symbol->getName();413414// Check the qualifier from the variable, not from the symbol node. The node may have a415// different qualifier if it's the result of a folded ternary node.416TQualifier qualifier = symbol->variable().getType().getQualifier();417const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();418419if (IsVaryingIn(qualifier))420{421if (interfaceBlock)422{423var = FindShaderIOBlockVariable(interfaceBlock->name(), mInputVaryings);424}425else426{427var = FindVariable(symbolName, mInputVaryings);428}429}430else if (IsVaryingOut(qualifier))431{432if (interfaceBlock)433{434var = FindShaderIOBlockVariable(interfaceBlock->name(), mOutputVaryings);435}436else437{438var = FindVariable(symbolName, mOutputVaryings);439}440}441else if (symbol->getType().getBasicType() == EbtInterfaceBlock)442{443UNREACHABLE();444}445else if (symbolName == "gl_DepthRange")446{447ASSERT(qualifier == EvqUniform);448449if (!mDepthRangeAdded)450{451ShaderVariable info;452const char kName[] = "gl_DepthRange";453info.name = kName;454info.mappedName = kName;455info.type = GL_NONE;456info.precision = GL_NONE;457info.staticUse = true;458info.active = true;459460ShaderVariable nearInfo(GL_FLOAT);461const char kNearName[] = "near";462nearInfo.name = kNearName;463nearInfo.mappedName = kNearName;464nearInfo.precision = GL_HIGH_FLOAT;465nearInfo.staticUse = true;466nearInfo.active = true;467468ShaderVariable farInfo(GL_FLOAT);469const char kFarName[] = "far";470farInfo.name = kFarName;471farInfo.mappedName = kFarName;472farInfo.precision = GL_HIGH_FLOAT;473farInfo.staticUse = true;474farInfo.active = true;475476ShaderVariable diffInfo(GL_FLOAT);477const char kDiffName[] = "diff";478diffInfo.name = kDiffName;479diffInfo.mappedName = kDiffName;480diffInfo.precision = GL_HIGH_FLOAT;481diffInfo.staticUse = true;482diffInfo.active = true;483484info.fields.push_back(nearInfo);485info.fields.push_back(farInfo);486info.fields.push_back(diffInfo);487488mUniforms->push_back(info);489mDepthRangeAdded = true;490}491}492else if (symbolName == "gl_NumSamples")493{494ASSERT(qualifier == EvqUniform);495496if (!mNumSamplesAdded)497{498ShaderVariable info;499const char kName[] = "gl_NumSamples";500info.name = kName;501info.mappedName = kName;502info.type = GL_INT;503info.precision = GL_LOW_INT;504info.staticUse = true;505info.active = true;506507mUniforms->push_back(info);508mNumSamplesAdded = true;509}510}511else512{513switch (qualifier)514{515case EvqAttribute:516case EvqVertexIn:517var = FindVariable(symbolName, mAttribs);518break;519case EvqFragmentOut:520case EvqFragmentInOut:521var = FindVariable(symbolName, mOutputVariables);522break;523case EvqUniform:524{525if (interfaceBlock)526{527var = FindVariableInInterfaceBlock(symbolName, interfaceBlock, mUniformBlocks);528}529else530{531var = FindVariable(symbolName, mUniforms);532}533534// It's an internal error to reference an undefined user uniform535ASSERT(!gl::IsBuiltInName(symbolName.data()) || var);536}537break;538case EvqBuffer:539{540var =541FindVariableInInterfaceBlock(symbolName, interfaceBlock, mShaderStorageBlocks);542}543break;544case EvqFragCoord:545recordBuiltInVaryingUsed(symbol->variable(), &mFragCoordAdded, mInputVaryings);546return;547case EvqFrontFacing:548recordBuiltInVaryingUsed(symbol->variable(), &mFrontFacingAdded, mInputVaryings);549return;550case EvqHelperInvocation:551recordBuiltInVaryingUsed(symbol->variable(), &mHelperInvocationAdded,552mInputVaryings);553return;554case EvqPointCoord:555recordBuiltInVaryingUsed(symbol->variable(), &mPointCoordAdded, mInputVaryings);556return;557case EvqNumWorkGroups:558recordBuiltInAttributeUsed(symbol->variable(), &mNumWorkGroupsAdded);559return;560case EvqWorkGroupID:561recordBuiltInAttributeUsed(symbol->variable(), &mWorkGroupIDAdded);562return;563case EvqLocalInvocationID:564recordBuiltInAttributeUsed(symbol->variable(), &mLocalInvocationIDAdded);565return;566case EvqGlobalInvocationID:567recordBuiltInAttributeUsed(symbol->variable(), &mGlobalInvocationIDAdded);568return;569case EvqLocalInvocationIndex:570recordBuiltInAttributeUsed(symbol->variable(), &mLocalInvocationIndexAdded);571return;572case EvqInstanceID:573// Whenever the SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW option is set,574// gl_InstanceID is added inside expressions to initialize ViewID_OVR and575// InstanceID. Note that gl_InstanceID is not added to the symbol table for ESSL1576// shaders.577recordBuiltInAttributeUsed(symbol->variable(), &mInstanceIDAdded);578return;579case EvqVertexID:580recordBuiltInAttributeUsed(symbol->variable(), &mVertexIDAdded);581return;582case EvqPosition:583recordBuiltInVaryingUsed(symbol->variable(), &mPositionAdded, mOutputVaryings);584return;585case EvqPointSize:586recordBuiltInVaryingUsed(symbol->variable(), &mPointSizeAdded, mOutputVaryings);587return;588case EvqDrawID:589recordBuiltInAttributeUsed(symbol->variable(), &mDrawIDAdded);590return;591case EvqLastFragData:592recordBuiltInVaryingUsed(symbol->variable(), &mLastFragDataAdded, mInputVaryings);593return;594case EvqFragColor:595recordBuiltInFragmentOutputUsed(symbol->variable(), &mFragColorAdded);596return;597case EvqFragData:598if (!mFragDataAdded)599{600ShaderVariable info;601setBuiltInInfoFromSymbol(symbol->variable(), &info);602if (!IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers))603{604ASSERT(info.arraySizes.size() == 1u);605info.arraySizes.back() = 1u;606}607info.active = true;608mOutputVariables->push_back(info);609mFragDataAdded = true;610}611return;612case EvqFragDepth:613recordBuiltInFragmentOutputUsed(symbol->variable(), &mFragDepthAdded);614return;615case EvqSecondaryFragColorEXT:616recordBuiltInFragmentOutputUsed(symbol->variable(), &mSecondaryFragColorEXTAdded);617return;618case EvqSecondaryFragDataEXT:619recordBuiltInFragmentOutputUsed(symbol->variable(), &mSecondaryFragDataEXTAdded);620return;621case EvqInvocationID:622recordBuiltInVaryingUsed(symbol->variable(), &mInvocationIDAdded, mInputVaryings);623break;624case EvqPrimitiveIDIn:625recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDInAdded, mInputVaryings);626break;627case EvqPrimitiveID:628if (mShaderType == GL_GEOMETRY_SHADER_EXT)629{630recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDAdded,631mOutputVaryings);632}633else634{635ASSERT(mShaderType == GL_FRAGMENT_SHADER ||636mShaderType == GL_TESS_CONTROL_SHADER ||637mShaderType == GL_TESS_EVALUATION_SHADER);638recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDAdded,639mInputVaryings);640}641break;642case EvqLayer:643if (mShaderType == GL_GEOMETRY_SHADER_EXT)644{645recordBuiltInVaryingUsed(symbol->variable(), &mLayerAdded, mOutputVaryings);646}647else if (mShaderType == GL_FRAGMENT_SHADER)648{649recordBuiltInVaryingUsed(symbol->variable(), &mLayerAdded, mInputVaryings);650}651else652{653ASSERT(mShaderType == GL_VERTEX_SHADER &&654(IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview2) ||655IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview)));656}657break;658case EvqShared:659if (mShaderType == GL_COMPUTE_SHADER)660{661recordBuiltInVaryingUsed(symbol->variable(), &mSharedVariableAdded,662mSharedVariables);663}664break;665case EvqClipDistance:666recordBuiltInVaryingUsed(667symbol->variable(), &mClipDistanceAdded,668mShaderType == GL_FRAGMENT_SHADER ? mInputVaryings : mOutputVaryings);669return;670case EvqCullDistance:671recordBuiltInVaryingUsed(672symbol->variable(), &mCullDistanceAdded,673mShaderType == GL_FRAGMENT_SHADER ? mInputVaryings : mOutputVaryings);674return;675case EvqSampleID:676recordBuiltInVaryingUsed(symbol->variable(), &mSampleIDAdded, mInputVaryings);677return;678case EvqSamplePosition:679recordBuiltInVaryingUsed(symbol->variable(), &mSamplePositionAdded, mInputVaryings);680return;681case EvqSampleMaskIn:682recordBuiltInVaryingUsed(symbol->variable(), &mSampleMaskInAdded, mInputVaryings);683return;684case EvqSampleMask:685recordBuiltInFragmentOutputUsed(symbol->variable(), &mSampleMaskAdded);686return;687case EvqPatchVerticesIn:688recordBuiltInVaryingUsed(symbol->variable(), &mPatchVerticesInAdded,689mInputVaryings);690break;691case EvqTessCoord:692recordBuiltInVaryingUsed(symbol->variable(), &mTessCoordAdded, mInputVaryings);693break;694case EvqTessLevelOuter:695if (mShaderType == GL_TESS_CONTROL_SHADER)696{697recordBuiltInVaryingUsed(symbol->variable(), &mTessLevelOuterAdded,698mOutputVaryings);699}700else701{702ASSERT(mShaderType == GL_TESS_EVALUATION_SHADER);703recordBuiltInVaryingUsed(symbol->variable(), &mTessLevelOuterAdded,704mInputVaryings);705}706break;707case EvqTessLevelInner:708if (mShaderType == GL_TESS_CONTROL_SHADER)709{710recordBuiltInVaryingUsed(symbol->variable(), &mTessLevelInnerAdded,711mOutputVaryings);712}713else714{715ASSERT(mShaderType == GL_TESS_EVALUATION_SHADER);716recordBuiltInVaryingUsed(symbol->variable(), &mTessLevelInnerAdded,717mInputVaryings);718}719break;720case EvqBoundingBoxEXT:721recordBuiltInVaryingUsed(symbol->variable(), &mBoundingBoxEXTAdded,722mOutputVaryings);723break;724default:725break;726}727}728if (var)729{730MarkActive(var);731}732}733734void CollectVariablesTraverser::setFieldOrVariableProperties(const TType &type,735bool staticUse,736bool isShaderIOBlock,737bool isPatch,738ShaderVariable *variableOut) const739{740ASSERT(variableOut);741742variableOut->staticUse = staticUse;743variableOut->isShaderIOBlock = isShaderIOBlock;744variableOut->isPatch = isPatch;745746const TStructure *structure = type.getStruct();747const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();748if (structure)749{750// Structures use a NONE type that isn't exposed outside ANGLE.751variableOut->type = GL_NONE;752if (structure->symbolType() != SymbolType::Empty)753{754variableOut->structOrBlockName = structure->name().data();755}756757const TFieldList &fields = structure->fields();758759for (const TField *field : fields)760{761// Regardless of the variable type (uniform, in/out etc.) its fields are always plain762// ShaderVariable objects.763ShaderVariable fieldVariable;764setFieldProperties(*field->type(), field->name(), staticUse, isShaderIOBlock, isPatch,765&fieldVariable);766variableOut->fields.push_back(fieldVariable);767}768}769else if (interfaceBlock && isShaderIOBlock)770{771variableOut->type = GL_NONE;772if (interfaceBlock->symbolType() != SymbolType::Empty)773{774variableOut->structOrBlockName = interfaceBlock->name().data();775variableOut->mappedStructOrBlockName =776HashName(interfaceBlock->name(), mHashFunction, nullptr).data();777}778const TFieldList &fields = interfaceBlock->fields();779for (const TField *field : fields)780{781ShaderVariable fieldVariable;782setFieldProperties(*field->type(), field->name(), staticUse, true, isPatch,783&fieldVariable);784fieldVariable.isShaderIOBlock = true;785variableOut->fields.push_back(fieldVariable);786}787}788else789{790variableOut->type = GLVariableType(type);791variableOut->precision = GLVariablePrecision(type);792}793794const TSpan<const unsigned int> &arraySizes = type.getArraySizes();795if (!arraySizes.empty())796{797variableOut->arraySizes.assign(arraySizes.begin(), arraySizes.end());798799if (arraySizes[0] == 0)800{801// Tessellation Control & Evaluation shader inputs:802// Declaring an array size is optional. If no size is specified, it will be taken from803// the implementation-dependent maximum patch size (gl_MaxPatchVertices).804if (type.getQualifier() == EvqTessControlIn ||805type.getQualifier() == EvqTessEvaluationIn)806{807variableOut->arraySizes[0] = mResources.MaxPatchVertices;808}809810// Tessellation Control shader outputs:811// Declaring an array size is optional. If no size is specified, it will be taken from812// output patch size declared in the shader.813if (type.getQualifier() == EvqTessControlOut)814{815ASSERT(mTessControlShaderOutputVertices > 0);816variableOut->arraySizes[0] = mTessControlShaderOutputVertices;817}818}819}820}821822void CollectVariablesTraverser::setFieldProperties(const TType &type,823const ImmutableString &name,824bool staticUse,825bool isShaderIOBlock,826bool isPatch,827ShaderVariable *variableOut) const828{829ASSERT(variableOut);830setFieldOrVariableProperties(type, staticUse, isShaderIOBlock, isPatch, variableOut);831variableOut->name.assign(name.data(), name.length());832variableOut->mappedName = HashName(name, mHashFunction, nullptr).data();833}834835void CollectVariablesTraverser::setCommonVariableProperties(const TType &type,836const TVariable &variable,837ShaderVariable *variableOut) const838{839ASSERT(variableOut);840ASSERT(type.getInterfaceBlock() == nullptr || IsShaderIoBlock(type.getQualifier()) ||841type.getQualifier() == EvqPatchIn || type.getQualifier() == EvqPatchOut);842843const bool staticUse = mSymbolTable->isStaticallyUsed(variable);844const bool isShaderIOBlock = type.getInterfaceBlock() != nullptr;845const bool isPatch = type.getQualifier() == EvqPatchIn || type.getQualifier() == EvqPatchOut;846847setFieldOrVariableProperties(type, staticUse, isShaderIOBlock, isPatch, variableOut);848849const bool isNamed = variable.symbolType() != SymbolType::Empty;850851ASSERT(isNamed || isShaderIOBlock);852if (isNamed)853{854variableOut->name.assign(variable.name().data(), variable.name().length());855variableOut->mappedName = getMappedName(&variable);856}857858// For I/O blocks, additionally store the name of the block as blockName. If the variable is859// unnamed, this name will be used instead for the purpose of interface matching.860if (isShaderIOBlock)861{862const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();863ASSERT(interfaceBlock);864865variableOut->structOrBlockName.assign(interfaceBlock->name().data(),866interfaceBlock->name().length());867variableOut->mappedStructOrBlockName =868HashName(interfaceBlock->name(), mHashFunction, nullptr).data();869variableOut->isShaderIOBlock = true;870}871}872873ShaderVariable CollectVariablesTraverser::recordAttribute(const TIntermSymbol &variable) const874{875const TType &type = variable.getType();876ASSERT(!type.getStruct());877878ShaderVariable attribute;879setCommonVariableProperties(type, variable.variable(), &attribute);880881attribute.location = type.getLayoutQualifier().location;882return attribute;883}884885ShaderVariable CollectVariablesTraverser::recordOutputVariable(const TIntermSymbol &variable) const886{887const TType &type = variable.getType();888ASSERT(!type.getStruct());889890ShaderVariable outputVariable;891setCommonVariableProperties(type, variable.variable(), &outputVariable);892893outputVariable.location = type.getLayoutQualifier().location;894outputVariable.index = type.getLayoutQualifier().index;895outputVariable.yuv = type.getLayoutQualifier().yuv;896return outputVariable;897}898899ShaderVariable CollectVariablesTraverser::recordVarying(const TIntermSymbol &variable) const900{901const TType &type = variable.getType();902903ShaderVariable varying;904setCommonVariableProperties(type, variable.variable(), &varying);905varying.location = type.getLayoutQualifier().location;906907switch (type.getQualifier())908{909case EvqVaryingIn:910case EvqVaryingOut:911case EvqVertexOut:912case EvqSmoothOut:913case EvqFlatOut:914case EvqNoPerspectiveOut:915case EvqCentroidOut:916case EvqGeometryOut:917case EvqSampleOut:918if (mSymbolTable->isVaryingInvariant(variable.variable()) || type.isInvariant())919{920varying.isInvariant = true;921}922break;923case EvqPatchIn:924case EvqPatchOut:925varying.isPatch = true;926break;927default:928break;929}930931varying.interpolation = GetInterpolationType(type.getQualifier());932933// Shader I/O block properties934if (type.getBasicType() == EbtInterfaceBlock)935{936bool isBlockImplicitLocation = false;937int location = type.getLayoutQualifier().location;938939// when a interface has not location in layout, assign to the zero.940if (location < 0)941{942location = 0;943isBlockImplicitLocation = true;944}945946const TInterfaceBlock *blockType = type.getInterfaceBlock();947ASSERT(blockType->fields().size() == varying.fields.size());948949for (size_t fieldIndex = 0; fieldIndex < varying.fields.size(); ++fieldIndex)950{951const TField *blockField = blockType->fields()[fieldIndex];952ShaderVariable &fieldVariable = varying.fields[fieldIndex];953const TType &fieldType = *blockField->type();954955fieldVariable.hasImplicitLocation = isBlockImplicitLocation;956fieldVariable.isPatch = varying.isPatch;957958int fieldLocation = fieldType.getLayoutQualifier().location;959if (fieldLocation >= 0)960{961fieldVariable.hasImplicitLocation = false;962fieldVariable.location = fieldLocation;963location = fieldLocation;964}965else966{967fieldVariable.location = location;968location += fieldType.getLocationCount();969}970971if (fieldType.getQualifier() != EvqGlobal)972{973fieldVariable.interpolation = GetFieldInterpolationType(fieldType.getQualifier());974}975}976}977978return varying;979}980981void CollectVariablesTraverser::recordInterfaceBlock(const char *instanceName,982const TType &interfaceBlockType,983InterfaceBlock *interfaceBlock) const984{985ASSERT(interfaceBlockType.getBasicType() == EbtInterfaceBlock);986ASSERT(interfaceBlock);987988const TInterfaceBlock *blockType = interfaceBlockType.getInterfaceBlock();989ASSERT(blockType);990991interfaceBlock->name = blockType->name().data();992interfaceBlock->mappedName = getMappedName(blockType);993994const bool isGLInBuiltin = (instanceName != nullptr) && strncmp(instanceName, "gl_in", 5u) == 0;995if (instanceName != nullptr)996{997interfaceBlock->instanceName = instanceName;998const TSymbol *blockSymbol = nullptr;999if (isGLInBuiltin)1000{1001blockSymbol = mSymbolTable->getGlInVariableWithArraySize();1002}1003else1004{1005blockSymbol = mSymbolTable->findGlobal(ImmutableString(instanceName));1006}1007ASSERT(blockSymbol && blockSymbol->isVariable());1008interfaceBlock->staticUse =1009mSymbolTable->isStaticallyUsed(*static_cast<const TVariable *>(blockSymbol));1010}10111012ASSERT(!interfaceBlockType.isArrayOfArrays()); // Disallowed by GLSL ES 3.10 section 4.3.91013interfaceBlock->arraySize =1014interfaceBlockType.isArray() ? interfaceBlockType.getOutermostArraySize() : 0;10151016interfaceBlock->blockType = GetBlockType(interfaceBlockType.getQualifier());1017if (interfaceBlock->blockType == BlockType::BLOCK_UNIFORM ||1018interfaceBlock->blockType == BlockType::BLOCK_BUFFER)1019{1020// TODO(oetuaho): Remove setting isRowMajorLayout.1021interfaceBlock->isRowMajorLayout = false;1022interfaceBlock->binding = blockType->blockBinding();1023interfaceBlock->layout = GetBlockLayoutType(blockType->blockStorage());1024}10251026// Gather field information1027bool anyFieldStaticallyUsed = false;10281029for (const TField *field : blockType->fields())1030{1031const TType &fieldType = *field->type();10321033bool staticUse = false;1034if (instanceName == nullptr)1035{1036// Static use of individual fields has been recorded, since they are present in the1037// symbol table as variables.1038const TSymbol *fieldSymbol = mSymbolTable->findGlobal(field->name());1039ASSERT(fieldSymbol && fieldSymbol->isVariable());1040staticUse =1041mSymbolTable->isStaticallyUsed(*static_cast<const TVariable *>(fieldSymbol));1042if (staticUse)1043{1044anyFieldStaticallyUsed = true;1045}1046}10471048ShaderVariable fieldVariable;1049setFieldProperties(fieldType, field->name(), staticUse, false, false, &fieldVariable);1050fieldVariable.isRowMajorLayout =1051(fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);1052interfaceBlock->fields.push_back(fieldVariable);1053}1054if (anyFieldStaticallyUsed)1055{1056interfaceBlock->staticUse = true;1057}1058}10591060ShaderVariable CollectVariablesTraverser::recordUniform(const TIntermSymbol &variable) const1061{1062ShaderVariable uniform;1063setCommonVariableProperties(variable.getType(), variable.variable(), &uniform);1064uniform.binding = variable.getType().getLayoutQualifier().binding;1065uniform.imageUnitFormat =1066GetImageInternalFormatType(variable.getType().getLayoutQualifier().imageInternalFormat);1067uniform.location = variable.getType().getLayoutQualifier().location;1068uniform.offset = variable.getType().getLayoutQualifier().offset;1069uniform.readonly = variable.getType().getMemoryQualifier().readonly;1070uniform.writeonly = variable.getType().getMemoryQualifier().writeonly;1071return uniform;1072}10731074bool CollectVariablesTraverser::visitDeclaration(Visit, TIntermDeclaration *node)1075{1076const TIntermSequence &sequence = *(node->getSequence());1077ASSERT(!sequence.empty());10781079const TIntermTyped &typedNode = *(sequence.front()->getAsTyped());1080TQualifier qualifier = typedNode.getQualifier();10811082bool isShaderVariable = qualifier == EvqAttribute || qualifier == EvqVertexIn ||1083qualifier == EvqFragmentOut || qualifier == EvqFragmentInOut ||1084qualifier == EvqUniform || IsVarying(qualifier);10851086if (typedNode.getBasicType() != EbtInterfaceBlock && !isShaderVariable)1087{1088return true;1089}10901091for (TIntermNode *variableNode : sequence)1092{1093// The only case in which the sequence will not contain a TIntermSymbol node is1094// initialization. It will contain a TInterBinary node in that case. Since attributes,1095// uniforms, varyings, outputs and interface blocks cannot be initialized in a shader, we1096// must have only TIntermSymbol nodes in the sequence in the cases we are interested in.1097const TIntermSymbol &variable = *variableNode->getAsSymbolNode();1098if (variable.variable().symbolType() == SymbolType::AngleInternal)1099{1100// Internal variables are not collected.1101continue;1102}11031104// SpirvTransformer::transform uses a map of ShaderVariables, it needs member variables and1105// (named or unnamed) structure as ShaderVariable. at link between two shaders, validation1106// between of named and unnamed, needs the same structure, its members, and members order1107// except instance name.1108if (typedNode.getBasicType() == EbtInterfaceBlock && !IsShaderIoBlock(qualifier) &&1109qualifier != EvqPatchIn && qualifier != EvqPatchOut)1110{1111InterfaceBlock interfaceBlock;1112bool isUnnamed = variable.variable().symbolType() == SymbolType::Empty;1113const TType &type = variable.getType();1114recordInterfaceBlock(isUnnamed ? nullptr : variable.getName().data(), type,1115&interfaceBlock);11161117// all fields in interface block will be added for updating interface variables because1118// the temporal structure variable will be ignored.1119switch (qualifier)1120{1121case EvqUniform:1122mUniformBlocks->push_back(interfaceBlock);1123break;1124case EvqBuffer:1125mShaderStorageBlocks->push_back(interfaceBlock);1126break;1127default:1128UNREACHABLE();1129}1130}1131else1132{1133ASSERT(variable.variable().symbolType() != SymbolType::Empty ||1134IsShaderIoBlock(qualifier) || qualifier == EvqPatchIn ||1135qualifier == EvqPatchOut);1136switch (qualifier)1137{1138case EvqAttribute:1139case EvqVertexIn:1140mAttribs->push_back(recordAttribute(variable));1141break;1142case EvqFragmentOut:1143case EvqFragmentInOut:1144mOutputVariables->push_back(recordOutputVariable(variable));1145break;1146case EvqUniform:1147mUniforms->push_back(recordUniform(variable));1148break;1149default:1150if (IsVaryingIn(qualifier))1151{1152mInputVaryings->push_back(recordVarying(variable));1153}1154else1155{1156ASSERT(IsVaryingOut(qualifier));1157mOutputVaryings->push_back(recordVarying(variable));1158}1159break;1160}1161}1162}11631164// None of the recorded variables can have initializers, so we don't need to traverse the1165// declarators.1166return false;1167}11681169InterfaceBlock *CollectVariablesTraverser::findNamedInterfaceBlock(1170const ImmutableString &blockName) const1171{1172InterfaceBlock *namedBlock = FindVariable(blockName, mUniformBlocks);1173if (!namedBlock)1174{1175namedBlock = FindVariable(blockName, mShaderStorageBlocks);1176}1177return namedBlock;1178}11791180bool CollectVariablesTraverser::visitBinary(Visit, TIntermBinary *binaryNode)1181{1182if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock)1183{1184// NOTE: we do not determine static use / activeness for individual blocks of an array.1185TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped();1186ASSERT(blockNode);11871188TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion();1189ASSERT(constantUnion);11901191InterfaceBlock *namedBlock = nullptr;11921193bool traverseIndexExpression = false;1194TIntermBinary *interfaceIndexingNode = blockNode->getAsBinaryNode();1195if (interfaceIndexingNode)1196{1197ASSERT(interfaceIndexingNode->getOp() == EOpIndexDirect ||1198interfaceIndexingNode->getOp() == EOpIndexIndirect);1199traverseIndexExpression = true;1200blockNode = interfaceIndexingNode->getLeft();1201}12021203const TType &interfaceNodeType = blockNode->getType();1204const TInterfaceBlock *interfaceBlock = interfaceNodeType.getInterfaceBlock();1205const TQualifier qualifier = interfaceNodeType.getQualifier();12061207// If it's a shader I/O block, look in varyings1208ShaderVariable *ioBlockVar = nullptr;1209if (qualifier == EvqPerVertexIn)1210{1211TIntermSymbol *symbolNode = blockNode->getAsSymbolNode();1212ASSERT(symbolNode);1213recordBuiltInVaryingUsed(symbolNode->variable(), &mPerVertexInAdded, mInputVaryings);1214ioBlockVar = FindShaderIOBlockVariable(interfaceBlock->name(), mInputVaryings);1215}1216else if (IsVaryingIn(qualifier))1217{1218ioBlockVar = FindShaderIOBlockVariable(interfaceBlock->name(), mInputVaryings);1219}1220else if (qualifier == EvqPerVertexOut)1221{1222TIntermSymbol *symbolNode = blockNode->getAsSymbolNode();1223ASSERT(symbolNode);1224recordBuiltInVaryingUsed(symbolNode->variable(), &mPerVertexOutAdded, mOutputVaryings);1225ioBlockVar = FindShaderIOBlockVariable(interfaceBlock->name(), mOutputVaryings);1226}1227else if (IsVaryingOut(qualifier))1228{1229ioBlockVar = FindShaderIOBlockVariable(interfaceBlock->name(), mOutputVaryings);1230}12311232if (ioBlockVar)1233{1234MarkActive(ioBlockVar);1235}1236else1237{1238if (!namedBlock)1239{1240namedBlock = findNamedInterfaceBlock(interfaceBlock->name());1241}1242ASSERT(namedBlock);1243ASSERT(namedBlock->staticUse);1244namedBlock->active = true;1245unsigned int fieldIndex = static_cast<unsigned int>(constantUnion->getIConst(0));1246ASSERT(fieldIndex < namedBlock->fields.size());1247// TODO(oetuaho): Would be nicer to record static use of fields of named interface1248// blocks more accurately at parse time - now we only mark the fields statically used if1249// they are active. http://anglebug.com/2440 We need to mark this field and all of its1250// sub-fields, as static/active1251MarkActive(&namedBlock->fields[fieldIndex]);1252}12531254if (traverseIndexExpression)1255{1256ASSERT(interfaceIndexingNode);1257interfaceIndexingNode->getRight()->traverse(this);1258}1259return false;1260}12611262return true;1263}12641265} // anonymous namespace12661267void CollectVariables(TIntermBlock *root,1268std::vector<ShaderVariable> *attributes,1269std::vector<ShaderVariable> *outputVariables,1270std::vector<ShaderVariable> *uniforms,1271std::vector<ShaderVariable> *inputVaryings,1272std::vector<ShaderVariable> *outputVaryings,1273std::vector<ShaderVariable> *sharedVariables,1274std::vector<InterfaceBlock> *uniformBlocks,1275std::vector<InterfaceBlock> *shaderStorageBlocks,1276ShHashFunction64 hashFunction,1277TSymbolTable *symbolTable,1278GLenum shaderType,1279const TExtensionBehavior &extensionBehavior,1280const ShBuiltInResources &resources,1281int tessControlShaderOutputVertices)1282{1283CollectVariablesTraverser collect(1284attributes, outputVariables, uniforms, inputVaryings, outputVaryings, sharedVariables,1285uniformBlocks, shaderStorageBlocks, hashFunction, symbolTable, shaderType,1286extensionBehavior, resources, tessControlShaderOutputVertices);1287root->traverse(&collect);1288}12891290} // namespace sh129112921293