summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src/compiler/translator/CollectVariables.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/angle/src/compiler/translator/CollectVariables.cpp')
-rw-r--r--src/3rdparty/angle/src/compiler/translator/CollectVariables.cpp869
1 files changed, 869 insertions, 0 deletions
diff --git a/src/3rdparty/angle/src/compiler/translator/CollectVariables.cpp b/src/3rdparty/angle/src/compiler/translator/CollectVariables.cpp
new file mode 100644
index 0000000000..bd8cbc971a
--- /dev/null
+++ b/src/3rdparty/angle/src/compiler/translator/CollectVariables.cpp
@@ -0,0 +1,869 @@
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// CollectVariables.cpp: Collect lists of shader interface variables based on the AST.
+
+#include "compiler/translator/CollectVariables.h"
+
+#include "angle_gl.h"
+#include "common/utilities.h"
+#include "compiler/translator/HashNames.h"
+#include "compiler/translator/IntermTraverse.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+namespace
+{
+
+BlockLayoutType GetBlockLayoutType(TLayoutBlockStorage blockStorage)
+{
+ switch (blockStorage)
+ {
+ case EbsPacked:
+ return BLOCKLAYOUT_PACKED;
+ case EbsShared:
+ return BLOCKLAYOUT_SHARED;
+ case EbsStd140:
+ return BLOCKLAYOUT_STD140;
+ case EbsStd430:
+ return BLOCKLAYOUT_STD430;
+ default:
+ UNREACHABLE();
+ return BLOCKLAYOUT_SHARED;
+ }
+}
+
+// TODO(jiawei.shao@intel.com): implement GL_OES_shader_io_blocks.
+BlockType GetBlockType(TQualifier qualifier)
+{
+ switch (qualifier)
+ {
+ case EvqUniform:
+ return BlockType::BLOCK_UNIFORM;
+ case EvqBuffer:
+ return BlockType::BLOCK_BUFFER;
+ case EvqPerVertexIn:
+ return BlockType::BLOCK_IN;
+ default:
+ UNREACHABLE();
+ return BlockType::BLOCK_UNIFORM;
+ }
+}
+
+template <class VarT>
+VarT *FindVariable(const TString &name, std::vector<VarT> *infoList)
+{
+ // TODO(zmo): optimize this function.
+ for (size_t ii = 0; ii < infoList->size(); ++ii)
+ {
+ if ((*infoList)[ii].name.c_str() == name)
+ return &((*infoList)[ii]);
+ }
+
+ return nullptr;
+}
+
+// Note that this shouldn't be called for interface blocks - static use information is collected for
+// individual fields in case of interface blocks.
+void MarkStaticallyUsed(ShaderVariable *variable)
+{
+ if (!variable->staticUse)
+ {
+ if (variable->isStruct())
+ {
+ // Conservatively assume all fields are statically used as well.
+ for (auto &field : variable->fields)
+ {
+ MarkStaticallyUsed(&field);
+ }
+ }
+ variable->staticUse = true;
+ }
+}
+
+ShaderVariable *FindVariableInInterfaceBlock(const TString &name,
+ const TInterfaceBlock *interfaceBlock,
+ std::vector<InterfaceBlock> *infoList)
+{
+ ASSERT(interfaceBlock);
+ InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), infoList);
+ ASSERT(namedBlock);
+
+ // Set static use on the parent interface block here
+ namedBlock->staticUse = true;
+ return FindVariable(name, &namedBlock->fields);
+}
+
+// Traverses the intermediate tree to collect all attributes, uniforms, varyings, fragment outputs,
+// and interface blocks.
+class CollectVariablesTraverser : public TIntermTraverser
+{
+ public:
+ CollectVariablesTraverser(std::vector<Attribute> *attribs,
+ std::vector<OutputVariable> *outputVariables,
+ std::vector<Uniform> *uniforms,
+ std::vector<Varying> *inputVaryings,
+ std::vector<Varying> *outputVaryings,
+ std::vector<InterfaceBlock> *uniformBlocks,
+ std::vector<InterfaceBlock> *shaderStorageBlocks,
+ std::vector<InterfaceBlock> *inBlocks,
+ ShHashFunction64 hashFunction,
+ TSymbolTable *symbolTable,
+ int shaderVersion,
+ GLenum shaderType,
+ const TExtensionBehavior &extensionBehavior);
+
+ void visitSymbol(TIntermSymbol *symbol) override;
+ bool visitDeclaration(Visit, TIntermDeclaration *node) override;
+ bool visitBinary(Visit visit, TIntermBinary *binaryNode) override;
+
+ private:
+ std::string getMappedName(const TName &name) const;
+
+ void setCommonVariableProperties(const TType &type,
+ const TName &name,
+ ShaderVariable *variableOut) const;
+
+ Attribute recordAttribute(const TIntermSymbol &variable) const;
+ OutputVariable recordOutputVariable(const TIntermSymbol &variable) const;
+ Varying recordVarying(const TIntermSymbol &variable) const;
+ void recordInterfaceBlock(const TType &interfaceBlockType,
+ InterfaceBlock *interfaceBlock) const;
+ Uniform recordUniform(const TIntermSymbol &variable) const;
+
+ void setBuiltInInfoFromSymbolTable(const char *name, ShaderVariable *info);
+
+ void recordBuiltInVaryingUsed(const char *name,
+ bool *addedFlag,
+ std::vector<Varying> *varyings);
+ void recordBuiltInFragmentOutputUsed(const char *name, bool *addedFlag);
+ void recordBuiltInAttributeUsed(const char *name, bool *addedFlag);
+ InterfaceBlock *recordGLInUsed(const TType &glInType);
+ InterfaceBlock *findNamedInterfaceBlock(const TString &name) const;
+
+ std::vector<Attribute> *mAttribs;
+ std::vector<OutputVariable> *mOutputVariables;
+ std::vector<Uniform> *mUniforms;
+ std::vector<Varying> *mInputVaryings;
+ std::vector<Varying> *mOutputVaryings;
+ std::vector<InterfaceBlock> *mUniformBlocks;
+ std::vector<InterfaceBlock> *mShaderStorageBlocks;
+ std::vector<InterfaceBlock> *mInBlocks;
+
+ std::map<std::string, InterfaceBlockField *> mInterfaceBlockFields;
+
+ // Shader uniforms
+ bool mDepthRangeAdded;
+
+ // Vertex Shader builtins
+ bool mInstanceIDAdded;
+ bool mVertexIDAdded;
+ bool mPointSizeAdded;
+
+ // Vertex Shader and Geometry Shader builtins
+ bool mPositionAdded;
+
+ // Fragment Shader builtins
+ bool mPointCoordAdded;
+ bool mFrontFacingAdded;
+ bool mFragCoordAdded;
+ bool mLastFragDataAdded;
+ bool mFragColorAdded;
+ bool mFragDataAdded;
+ bool mFragDepthEXTAdded;
+ bool mFragDepthAdded;
+ bool mSecondaryFragColorEXTAdded;
+ bool mSecondaryFragDataEXTAdded;
+
+ // Geometry Shader builtins
+ bool mPerVertexInAdded;
+ bool mPrimitiveIDInAdded;
+ bool mInvocationIDAdded;
+
+ // Geometry Shader and Fragment Shader builtins
+ bool mPrimitiveIDAdded;
+ bool mLayerAdded;
+
+ ShHashFunction64 mHashFunction;
+
+ int mShaderVersion;
+ GLenum mShaderType;
+ const TExtensionBehavior &mExtensionBehavior;
+};
+
+CollectVariablesTraverser::CollectVariablesTraverser(
+ std::vector<sh::Attribute> *attribs,
+ std::vector<sh::OutputVariable> *outputVariables,
+ std::vector<sh::Uniform> *uniforms,
+ std::vector<sh::Varying> *inputVaryings,
+ std::vector<sh::Varying> *outputVaryings,
+ std::vector<sh::InterfaceBlock> *uniformBlocks,
+ std::vector<sh::InterfaceBlock> *shaderStorageBlocks,
+ std::vector<sh::InterfaceBlock> *inBlocks,
+ ShHashFunction64 hashFunction,
+ TSymbolTable *symbolTable,
+ int shaderVersion,
+ GLenum shaderType,
+ const TExtensionBehavior &extensionBehavior)
+ : TIntermTraverser(true, false, false, symbolTable),
+ mAttribs(attribs),
+ mOutputVariables(outputVariables),
+ mUniforms(uniforms),
+ mInputVaryings(inputVaryings),
+ mOutputVaryings(outputVaryings),
+ mUniformBlocks(uniformBlocks),
+ mShaderStorageBlocks(shaderStorageBlocks),
+ mInBlocks(inBlocks),
+ mDepthRangeAdded(false),
+ mInstanceIDAdded(false),
+ mVertexIDAdded(false),
+ mPointSizeAdded(false),
+ mPositionAdded(false),
+ mPointCoordAdded(false),
+ mFrontFacingAdded(false),
+ mFragCoordAdded(false),
+ mLastFragDataAdded(false),
+ mFragColorAdded(false),
+ mFragDataAdded(false),
+ mFragDepthEXTAdded(false),
+ mFragDepthAdded(false),
+ mSecondaryFragColorEXTAdded(false),
+ mSecondaryFragDataEXTAdded(false),
+ mPerVertexInAdded(false),
+ mPrimitiveIDInAdded(false),
+ mInvocationIDAdded(false),
+ mPrimitiveIDAdded(false),
+ mLayerAdded(false),
+ mHashFunction(hashFunction),
+ mShaderVersion(shaderVersion),
+ mShaderType(shaderType),
+ mExtensionBehavior(extensionBehavior)
+{
+}
+
+std::string CollectVariablesTraverser::getMappedName(const TName &name) const
+{
+ return HashName(name, mHashFunction, nullptr).c_str();
+}
+
+void CollectVariablesTraverser::setBuiltInInfoFromSymbolTable(const char *name,
+ ShaderVariable *info)
+{
+ TVariable *symbolTableVar =
+ reinterpret_cast<TVariable *>(mSymbolTable->findBuiltIn(name, mShaderVersion));
+ ASSERT(symbolTableVar);
+ const TType &type = symbolTableVar->getType();
+
+ info->name = name;
+ info->mappedName = name;
+ info->type = GLVariableType(type);
+ info->precision = GLVariablePrecision(type);
+ if (auto *arraySizes = type.getArraySizes())
+ {
+ info->arraySizes.assign(arraySizes->begin(), arraySizes->end());
+ }
+}
+
+void CollectVariablesTraverser::recordBuiltInVaryingUsed(const char *name,
+ bool *addedFlag,
+ std::vector<Varying> *varyings)
+{
+ ASSERT(varyings);
+ if (!(*addedFlag))
+ {
+ Varying info;
+ setBuiltInInfoFromSymbolTable(name, &info);
+ info.staticUse = true;
+ info.isInvariant = mSymbolTable->isVaryingInvariant(name);
+ varyings->push_back(info);
+ (*addedFlag) = true;
+ }
+}
+
+void CollectVariablesTraverser::recordBuiltInFragmentOutputUsed(const char *name, bool *addedFlag)
+{
+ if (!(*addedFlag))
+ {
+ OutputVariable info;
+ setBuiltInInfoFromSymbolTable(name, &info);
+ info.staticUse = true;
+ mOutputVariables->push_back(info);
+ (*addedFlag) = true;
+ }
+}
+
+void CollectVariablesTraverser::recordBuiltInAttributeUsed(const char *name, bool *addedFlag)
+{
+ if (!(*addedFlag))
+ {
+ Attribute info;
+ setBuiltInInfoFromSymbolTable(name, &info);
+ info.staticUse = true;
+ info.location = -1;
+ mAttribs->push_back(info);
+ (*addedFlag) = true;
+ }
+}
+
+InterfaceBlock *CollectVariablesTraverser::recordGLInUsed(const TType &glInType)
+{
+ if (!mPerVertexInAdded)
+ {
+ ASSERT(glInType.getQualifier() == EvqPerVertexIn);
+ InterfaceBlock info;
+ recordInterfaceBlock(glInType, &info);
+ info.staticUse = true;
+
+ mPerVertexInAdded = true;
+ mInBlocks->push_back(info);
+ return &mInBlocks->back();
+ }
+ else
+ {
+ return FindVariable("gl_PerVertex", mInBlocks);
+ }
+}
+
+// We want to check whether a uniform/varying is statically used
+// because we only count the used ones in packing computing.
+// Also, gl_FragCoord, gl_PointCoord, and gl_FrontFacing count
+// toward varying counting if they are statically used in a fragment
+// shader.
+void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol)
+{
+ ASSERT(symbol != nullptr);
+
+ if (symbol->getName().isInternal())
+ {
+ // Internal variables are not collected.
+ return;
+ }
+
+ ShaderVariable *var = nullptr;
+ const TString &symbolName = symbol->getName().getString();
+
+ if (IsVaryingIn(symbol->getQualifier()))
+ {
+ var = FindVariable(symbolName, mInputVaryings);
+ }
+ else if (IsVaryingOut(symbol->getQualifier()))
+ {
+ var = FindVariable(symbolName, mOutputVaryings);
+ }
+ else if (symbol->getType().getBasicType() == EbtInterfaceBlock)
+ {
+ UNREACHABLE();
+ }
+ else if (symbolName == "gl_DepthRange")
+ {
+ ASSERT(symbol->getQualifier() == EvqUniform);
+
+ if (!mDepthRangeAdded)
+ {
+ Uniform info;
+ const char kName[] = "gl_DepthRange";
+ info.name = kName;
+ info.mappedName = kName;
+ info.type = GL_NONE;
+ info.precision = GL_NONE;
+ info.staticUse = true;
+
+ ShaderVariable nearInfo(GL_FLOAT);
+ const char kNearName[] = "near";
+ nearInfo.name = kNearName;
+ nearInfo.mappedName = kNearName;
+ nearInfo.precision = GL_HIGH_FLOAT;
+ nearInfo.staticUse = true;
+
+ ShaderVariable farInfo(GL_FLOAT);
+ const char kFarName[] = "far";
+ farInfo.name = kFarName;
+ farInfo.mappedName = kFarName;
+ farInfo.precision = GL_HIGH_FLOAT;
+ farInfo.staticUse = true;
+
+ ShaderVariable diffInfo(GL_FLOAT);
+ const char kDiffName[] = "diff";
+ diffInfo.name = kDiffName;
+ diffInfo.mappedName = kDiffName;
+ diffInfo.precision = GL_HIGH_FLOAT;
+ diffInfo.staticUse = true;
+
+ info.fields.push_back(nearInfo);
+ info.fields.push_back(farInfo);
+ info.fields.push_back(diffInfo);
+
+ mUniforms->push_back(info);
+ mDepthRangeAdded = true;
+ }
+ }
+ else
+ {
+ switch (symbol->getQualifier())
+ {
+ case EvqAttribute:
+ case EvqVertexIn:
+ var = FindVariable(symbolName, mAttribs);
+ break;
+ case EvqFragmentOut:
+ var = FindVariable(symbolName, mOutputVariables);
+ break;
+ case EvqUniform:
+ {
+ const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();
+ if (interfaceBlock)
+ {
+ var = FindVariableInInterfaceBlock(symbolName, interfaceBlock, mUniformBlocks);
+ }
+ else
+ {
+ var = FindVariable(symbolName, mUniforms);
+ }
+
+ // It's an internal error to reference an undefined user uniform
+ ASSERT(symbolName.compare(0, 3, "gl_") != 0 || var);
+ }
+ break;
+ case EvqBuffer:
+ {
+ const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();
+ var =
+ FindVariableInInterfaceBlock(symbolName, interfaceBlock, mShaderStorageBlocks);
+ }
+ break;
+ case EvqFragCoord:
+ recordBuiltInVaryingUsed("gl_FragCoord", &mFragCoordAdded, mInputVaryings);
+ return;
+ case EvqFrontFacing:
+ recordBuiltInVaryingUsed("gl_FrontFacing", &mFrontFacingAdded, mInputVaryings);
+ return;
+ case EvqPointCoord:
+ recordBuiltInVaryingUsed("gl_PointCoord", &mPointCoordAdded, mInputVaryings);
+ return;
+ case EvqInstanceID:
+ // Whenever the SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW option is set,
+ // gl_InstanceID is added inside expressions to initialize ViewID_OVR and
+ // InstanceID. gl_InstanceID is not added to the symbol table for ESSL1 shaders
+ // which makes it necessary to populate the type information explicitly instead of
+ // extracting it from the symbol table.
+ if (!mInstanceIDAdded)
+ {
+ Attribute info;
+ const char kName[] = "gl_InstanceID";
+ info.name = kName;
+ info.mappedName = kName;
+ info.type = GL_INT;
+ info.precision = GL_HIGH_INT; // Defined by spec.
+ info.staticUse = true;
+ info.location = -1;
+ mAttribs->push_back(info);
+ mInstanceIDAdded = true;
+ }
+ return;
+ case EvqVertexID:
+ recordBuiltInAttributeUsed("gl_VertexID", &mVertexIDAdded);
+ return;
+ case EvqPosition:
+ recordBuiltInVaryingUsed("gl_Position", &mPositionAdded, mOutputVaryings);
+ return;
+ case EvqPointSize:
+ recordBuiltInVaryingUsed("gl_PointSize", &mPointSizeAdded, mOutputVaryings);
+ return;
+ case EvqLastFragData:
+ recordBuiltInVaryingUsed("gl_LastFragData", &mLastFragDataAdded, mInputVaryings);
+ return;
+ case EvqFragColor:
+ recordBuiltInFragmentOutputUsed("gl_FragColor", &mFragColorAdded);
+ return;
+ case EvqFragData:
+ if (!mFragDataAdded)
+ {
+ OutputVariable info;
+ setBuiltInInfoFromSymbolTable("gl_FragData", &info);
+ if (!IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers))
+ {
+ ASSERT(info.arraySizes.size() == 1u);
+ info.arraySizes.back() = 1u;
+ }
+ info.staticUse = true;
+ mOutputVariables->push_back(info);
+ mFragDataAdded = true;
+ }
+ return;
+ case EvqFragDepthEXT:
+ recordBuiltInFragmentOutputUsed("gl_FragDepthEXT", &mFragDepthEXTAdded);
+ return;
+ case EvqFragDepth:
+ recordBuiltInFragmentOutputUsed("gl_FragDepth", &mFragDepthAdded);
+ return;
+ case EvqSecondaryFragColorEXT:
+ recordBuiltInFragmentOutputUsed("gl_SecondaryFragColorEXT",
+ &mSecondaryFragColorEXTAdded);
+ return;
+ case EvqSecondaryFragDataEXT:
+ recordBuiltInFragmentOutputUsed("gl_SecondaryFragDataEXT",
+ &mSecondaryFragDataEXTAdded);
+ return;
+ case EvqInvocationID:
+ recordBuiltInVaryingUsed("gl_InvocationID", &mInvocationIDAdded, mInputVaryings);
+ break;
+ case EvqPrimitiveIDIn:
+ recordBuiltInVaryingUsed("gl_PrimitiveIDIn", &mPrimitiveIDInAdded, mInputVaryings);
+ break;
+ case EvqPrimitiveID:
+ if (mShaderType == GL_GEOMETRY_SHADER_OES)
+ {
+ recordBuiltInVaryingUsed("gl_PrimitiveID", &mPrimitiveIDAdded, mOutputVaryings);
+ }
+ else
+ {
+ ASSERT(mShaderType == GL_FRAGMENT_SHADER);
+ recordBuiltInVaryingUsed("gl_PrimitiveID", &mPrimitiveIDAdded, mInputVaryings);
+ }
+ break;
+ case EvqLayer:
+ if (mShaderType == GL_GEOMETRY_SHADER_OES)
+ {
+ recordBuiltInVaryingUsed("gl_Layer", &mLayerAdded, mOutputVaryings);
+ }
+ else if (mShaderType == GL_FRAGMENT_SHADER)
+ {
+ recordBuiltInVaryingUsed("gl_Layer", &mLayerAdded, mInputVaryings);
+ }
+ else
+ {
+ ASSERT(mShaderType == GL_VERTEX_SHADER &&
+ IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview));
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ if (var)
+ {
+ MarkStaticallyUsed(var);
+ }
+}
+
+void CollectVariablesTraverser::setCommonVariableProperties(const TType &type,
+ const TName &name,
+ ShaderVariable *variableOut) const
+{
+ ASSERT(variableOut);
+
+ const TStructure *structure = type.getStruct();
+
+ if (!structure)
+ {
+ variableOut->type = GLVariableType(type);
+ variableOut->precision = GLVariablePrecision(type);
+ }
+ else
+ {
+ // Structures use a NONE type that isn't exposed outside ANGLE.
+ variableOut->type = GL_NONE;
+ variableOut->structName = structure->name().c_str();
+
+ const TFieldList &fields = structure->fields();
+
+ for (TField *field : fields)
+ {
+ // Regardless of the variable type (uniform, in/out etc.) its fields are always plain
+ // ShaderVariable objects.
+ ShaderVariable fieldVariable;
+ setCommonVariableProperties(*field->type(), TName(field->name()), &fieldVariable);
+ variableOut->fields.push_back(fieldVariable);
+ }
+ }
+ variableOut->name = name.getString().c_str();
+ variableOut->mappedName = getMappedName(name);
+
+ if (auto *arraySizes = type.getArraySizes())
+ {
+ variableOut->arraySizes.assign(arraySizes->begin(), arraySizes->end());
+ }
+}
+
+Attribute CollectVariablesTraverser::recordAttribute(const TIntermSymbol &variable) const
+{
+ const TType &type = variable.getType();
+ ASSERT(!type.getStruct());
+
+ Attribute attribute;
+ setCommonVariableProperties(type, variable.getName(), &attribute);
+
+ attribute.location = type.getLayoutQualifier().location;
+ return attribute;
+}
+
+OutputVariable CollectVariablesTraverser::recordOutputVariable(const TIntermSymbol &variable) const
+{
+ const TType &type = variable.getType();
+ ASSERT(!type.getStruct());
+
+ OutputVariable outputVariable;
+ setCommonVariableProperties(type, variable.getName(), &outputVariable);
+
+ outputVariable.location = type.getLayoutQualifier().location;
+ return outputVariable;
+}
+
+Varying CollectVariablesTraverser::recordVarying(const TIntermSymbol &variable) const
+{
+ const TType &type = variable.getType();
+
+ Varying varying;
+ setCommonVariableProperties(type, variable.getName(), &varying);
+ varying.location = type.getLayoutQualifier().location;
+
+ switch (type.getQualifier())
+ {
+ case EvqVaryingIn:
+ case EvqVaryingOut:
+ case EvqVertexOut:
+ case EvqSmoothOut:
+ case EvqFlatOut:
+ case EvqCentroidOut:
+ case EvqGeometryOut:
+ if (mSymbolTable->isVaryingInvariant(std::string(variable.getSymbol().c_str())) ||
+ type.isInvariant())
+ {
+ varying.isInvariant = true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ varying.interpolation = GetInterpolationType(type.getQualifier());
+ return varying;
+}
+
+// TODO(jiawei.shao@intel.com): implement GL_OES_shader_io_blocks.
+void CollectVariablesTraverser::recordInterfaceBlock(const TType &interfaceBlockType,
+ InterfaceBlock *interfaceBlock) const
+{
+ ASSERT(interfaceBlockType.getBasicType() == EbtInterfaceBlock);
+ ASSERT(interfaceBlock);
+
+ const TInterfaceBlock *blockType = interfaceBlockType.getInterfaceBlock();
+ ASSERT(blockType);
+
+ interfaceBlock->name = blockType->name().c_str();
+ interfaceBlock->mappedName = getMappedName(TName(blockType->name()));
+ interfaceBlock->instanceName =
+ (blockType->hasInstanceName() ? blockType->instanceName().c_str() : "");
+ ASSERT(!interfaceBlockType.isArrayOfArrays()); // Disallowed by GLSL ES 3.10 section 4.3.9
+ interfaceBlock->arraySize = interfaceBlockType.isArray() ? interfaceBlockType.getOutermostArraySize() : 0;
+
+ interfaceBlock->blockType = GetBlockType(interfaceBlockType.getQualifier());
+ if (interfaceBlock->blockType == BlockType::BLOCK_UNIFORM ||
+ interfaceBlock->blockType == BlockType::BLOCK_BUFFER)
+ {
+ interfaceBlock->isRowMajorLayout = (blockType->matrixPacking() == EmpRowMajor);
+ interfaceBlock->binding = blockType->blockBinding();
+ interfaceBlock->layout = GetBlockLayoutType(blockType->blockStorage());
+ }
+
+ // Gather field information
+ for (const TField *field : blockType->fields())
+ {
+ const TType &fieldType = *field->type();
+
+ InterfaceBlockField fieldVariable;
+ setCommonVariableProperties(fieldType, TName(field->name()), &fieldVariable);
+ fieldVariable.isRowMajorLayout =
+ (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
+ interfaceBlock->fields.push_back(fieldVariable);
+ }
+}
+
+Uniform CollectVariablesTraverser::recordUniform(const TIntermSymbol &variable) const
+{
+ Uniform uniform;
+ setCommonVariableProperties(variable.getType(), variable.getName(), &uniform);
+ uniform.binding = variable.getType().getLayoutQualifier().binding;
+ uniform.location = variable.getType().getLayoutQualifier().location;
+ uniform.offset = variable.getType().getLayoutQualifier().offset;
+ return uniform;
+}
+
+bool CollectVariablesTraverser::visitDeclaration(Visit, TIntermDeclaration *node)
+{
+ const TIntermSequence &sequence = *(node->getSequence());
+ ASSERT(!sequence.empty());
+
+ const TIntermTyped &typedNode = *(sequence.front()->getAsTyped());
+ TQualifier qualifier = typedNode.getQualifier();
+
+ bool isShaderVariable = qualifier == EvqAttribute || qualifier == EvqVertexIn ||
+ qualifier == EvqFragmentOut || qualifier == EvqUniform ||
+ IsVarying(qualifier);
+
+ if (typedNode.getBasicType() != EbtInterfaceBlock && !isShaderVariable)
+ {
+ return true;
+ }
+
+ for (TIntermNode *variableNode : sequence)
+ {
+ // The only case in which the sequence will not contain a TIntermSymbol node is
+ // initialization. It will contain a TInterBinary node in that case. Since attributes,
+ // uniforms, varyings, outputs and interface blocks cannot be initialized in a shader, we
+ // must have only TIntermSymbol nodes in the sequence in the cases we are interested in.
+ const TIntermSymbol &variable = *variableNode->getAsSymbolNode();
+ if (variable.getName().isInternal())
+ {
+ // Internal variables are not collected.
+ continue;
+ }
+
+ // TODO(jiawei.shao@intel.com): implement GL_OES_shader_io_blocks.
+ if (typedNode.getBasicType() == EbtInterfaceBlock)
+ {
+ InterfaceBlock interfaceBlock;
+ recordInterfaceBlock(variable.getType(), &interfaceBlock);
+
+ switch (qualifier)
+ {
+ case EvqUniform:
+ mUniformBlocks->push_back(interfaceBlock);
+ break;
+ case EvqBuffer:
+ mShaderStorageBlocks->push_back(interfaceBlock);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+ else
+ {
+ switch (qualifier)
+ {
+ case EvqAttribute:
+ case EvqVertexIn:
+ mAttribs->push_back(recordAttribute(variable));
+ break;
+ case EvqFragmentOut:
+ mOutputVariables->push_back(recordOutputVariable(variable));
+ break;
+ case EvqUniform:
+ mUniforms->push_back(recordUniform(variable));
+ break;
+ default:
+ if (IsVaryingIn(qualifier))
+ {
+ mInputVaryings->push_back(recordVarying(variable));
+ }
+ else
+ {
+ ASSERT(IsVaryingOut(qualifier));
+ mOutputVaryings->push_back(recordVarying(variable));
+ }
+ break;
+ }
+ }
+ }
+
+ // None of the recorded variables can have initializers, so we don't need to traverse the
+ // declarators.
+ return false;
+}
+
+// TODO(jiawei.shao@intel.com): add search on mInBlocks and mOutBlocks when implementing
+// GL_OES_shader_io_blocks.
+InterfaceBlock *CollectVariablesTraverser::findNamedInterfaceBlock(const TString &blockName) const
+{
+ InterfaceBlock *namedBlock = FindVariable(blockName, mUniformBlocks);
+ if (!namedBlock)
+ {
+ namedBlock = FindVariable(blockName, mShaderStorageBlocks);
+ }
+ return namedBlock;
+}
+
+bool CollectVariablesTraverser::visitBinary(Visit, TIntermBinary *binaryNode)
+{
+ if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock)
+ {
+ // NOTE: we do not determine static use for individual blocks of an array
+ TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped();
+ ASSERT(blockNode);
+
+ TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion();
+ ASSERT(constantUnion);
+
+ InterfaceBlock *namedBlock = nullptr;
+
+ bool traverseIndexExpression = false;
+ TIntermBinary *interfaceIndexingNode = blockNode->getAsBinaryNode();
+ if (interfaceIndexingNode)
+ {
+ TIntermTyped *interfaceNode = interfaceIndexingNode->getLeft()->getAsTyped();
+ ASSERT(interfaceNode);
+
+ const TType &interfaceType = interfaceNode->getType();
+ if (interfaceType.getQualifier() == EvqPerVertexIn)
+ {
+ namedBlock = recordGLInUsed(interfaceType);
+ ASSERT(namedBlock);
+
+ // We need to continue traversing to collect useful variables in the index
+ // expression of gl_in.
+ traverseIndexExpression = true;
+ }
+ }
+
+ const TInterfaceBlock *interfaceBlock = blockNode->getType().getInterfaceBlock();
+ if (!namedBlock)
+ {
+ namedBlock = findNamedInterfaceBlock(interfaceBlock->name());
+ }
+ ASSERT(namedBlock);
+ namedBlock->staticUse = true;
+ unsigned int fieldIndex = static_cast<unsigned int>(constantUnion->getIConst(0));
+ ASSERT(fieldIndex < namedBlock->fields.size());
+ namedBlock->fields[fieldIndex].staticUse = true;
+
+ if (traverseIndexExpression)
+ {
+ ASSERT(interfaceIndexingNode);
+ interfaceIndexingNode->getRight()->traverse(this);
+ }
+ return false;
+ }
+
+ return true;
+}
+
+} // anonymous namespace
+
+void CollectVariables(TIntermBlock *root,
+ std::vector<Attribute> *attributes,
+ std::vector<OutputVariable> *outputVariables,
+ std::vector<Uniform> *uniforms,
+ std::vector<Varying> *inputVaryings,
+ std::vector<Varying> *outputVaryings,
+ std::vector<InterfaceBlock> *uniformBlocks,
+ std::vector<InterfaceBlock> *shaderStorageBlocks,
+ std::vector<InterfaceBlock> *inBlocks,
+ ShHashFunction64 hashFunction,
+ TSymbolTable *symbolTable,
+ int shaderVersion,
+ GLenum shaderType,
+ const TExtensionBehavior &extensionBehavior)
+{
+ CollectVariablesTraverser collect(attributes, outputVariables, uniforms, inputVaryings,
+ outputVaryings, uniformBlocks, shaderStorageBlocks, inBlocks,
+ hashFunction, symbolTable, shaderVersion, shaderType,
+ extensionBehavior);
+ root->traverse(&collect);
+}
+
+} // namespace sh