bool CollectVariables::visitAggregate(Visit, TIntermAggregate *node) { bool visitChildren = true; switch (node->getOp()) { case EOpDeclaration: { const TIntermSequence &sequence = *(node->getSequence()); ASSERT(!sequence.empty()); const TIntermTyped &typedNode = *(sequence.front()->getAsTyped()); TQualifier qualifier = typedNode.getQualifier(); if (typedNode.getBasicType() == EbtInterfaceBlock) { visitInfoList(sequence, mInterfaceBlocks); visitChildren = false; } else if (qualifier == EvqAttribute || qualifier == EvqVertexIn || qualifier == EvqFragmentOut || qualifier == EvqUniform || IsVarying(qualifier)) { switch (qualifier) { case EvqAttribute: case EvqVertexIn: visitInfoList(sequence, mAttribs); break; case EvqFragmentOut: visitInfoList(sequence, mOutputVariables); break; case EvqUniform: visitInfoList(sequence, mUniforms); break; default: visitInfoList(sequence, mVaryings); break; } visitChildren = false; } break; } default: break; } return visitChildren; }
// 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 CollectVariables::visitSymbol(TIntermSymbol *symbol) { ASSERT(symbol != NULL); ShaderVariable *var = NULL; const TString &symbolName = symbol->getSymbol(); if (IsVarying(symbol->getQualifier())) { var = FindVariable(symbolName, mVaryings); } 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_STRUCT_ANGLEX; info.arraySize = 0; info.precision = GL_NONE; info.staticUse = true; ShaderVariable nearInfo; const char kNearName[] = "near"; nearInfo.name = kNearName; nearInfo.mappedName = kNearName; nearInfo.type = GL_FLOAT; nearInfo.arraySize = 0; nearInfo.precision = GL_HIGH_FLOAT; nearInfo.staticUse = true; ShaderVariable farInfo; const char kFarName[] = "far"; farInfo.name = kFarName; farInfo.mappedName = kFarName; farInfo.type = GL_FLOAT; farInfo.arraySize = 0; farInfo.precision = GL_HIGH_FLOAT; farInfo.staticUse = true; ShaderVariable diffInfo; const char kDiffName[] = "diff"; diffInfo.name = kDiffName; diffInfo.mappedName = kDiffName; diffInfo.type = GL_FLOAT; diffInfo.arraySize = 0; 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) { InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), mInterfaceBlocks); ASSERT(namedBlock); var = FindVariable(symbolName, &namedBlock->fields); // Set static use on the parent interface block here namedBlock->staticUse = true; } 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 EvqFragCoord: if (!mFragCoordAdded) { Varying info; const char kName[] = "gl_FragCoord"; info.name = kName; info.mappedName = kName; info.type = GL_FLOAT_VEC4; info.arraySize = 0; info.precision = GL_MEDIUM_FLOAT; // Defined by spec. info.staticUse = true; info.isInvariant = mSymbolTable.isVaryingInvariant(kName); mVaryings->push_back(info); mFragCoordAdded = true; } return; case EvqFrontFacing: if (!mFrontFacingAdded) { Varying info; const char kName[] = "gl_FrontFacing"; info.name = kName; info.mappedName = kName; info.type = GL_BOOL; info.arraySize = 0; info.precision = GL_NONE; info.staticUse = true; info.isInvariant = mSymbolTable.isVaryingInvariant(kName); mVaryings->push_back(info); mFrontFacingAdded = true; } return; case EvqPointCoord: if (!mPointCoordAdded) { Varying info; const char kName[] = "gl_PointCoord"; info.name = kName; info.mappedName = kName; info.type = GL_FLOAT_VEC2; info.arraySize = 0; info.precision = GL_MEDIUM_FLOAT; // Defined by spec. info.staticUse = true; info.isInvariant = mSymbolTable.isVaryingInvariant(kName); mVaryings->push_back(info); mPointCoordAdded = true; } return; case EvqInstanceID: if (!mInstanceIDAdded) { Attribute info; const char kName[] = "gl_InstanceID"; info.name = kName; info.mappedName = kName; info.type = GL_INT; info.arraySize = 0; info.precision = GL_HIGH_INT; // Defined by spec. info.staticUse = true; info.location = -1; mAttribs->push_back(info); mInstanceIDAdded = true; } return; case EvqPosition: if (!mPositionAdded) { Varying info; const char kName[] = "gl_Position"; info.name = kName; info.mappedName = kName; info.type = GL_FLOAT_VEC4; info.arraySize = 0; info.precision = GL_HIGH_FLOAT; // Defined by spec. info.staticUse = true; info.isInvariant = mSymbolTable.isVaryingInvariant(kName); mVaryings->push_back(info); mPositionAdded = true; } return; case EvqPointSize: if (!mPointSizeAdded) { Varying info; const char kName[] = "gl_PointSize"; info.name = kName; info.mappedName = kName; info.type = GL_FLOAT; info.arraySize = 0; info.precision = GL_MEDIUM_FLOAT; // Defined by spec. info.staticUse = true; info.isInvariant = mSymbolTable.isVaryingInvariant(kName); mVaryings->push_back(info); mPointSizeAdded = true; } return; case EvqLastFragData: if (!mLastFragDataAdded) { Varying info; const char kName[] = "gl_LastFragData"; info.name = kName; info.mappedName = kName; info.type = GL_FLOAT_VEC4; info.arraySize = static_cast<const TVariable*>(mSymbolTable.findBuiltIn("gl_MaxDrawBuffers", 100))->getConstPointer()->getIConst(); info.precision = GL_MEDIUM_FLOAT; // Defined by spec. info.staticUse = true; info.isInvariant = mSymbolTable.isVaryingInvariant(kName); mVaryings->push_back(info); mLastFragDataAdded = true; } return; case EvqFragColor: if (!mFragColorAdded) { Attribute info; const char kName[] = "gl_FragColor"; info.name = kName; info.mappedName = kName; info.type = GL_FLOAT_VEC4; info.arraySize = 0; info.precision = GL_MEDIUM_FLOAT; // Defined by spec. info.staticUse = true; mOutputVariables->push_back(info); mFragColorAdded = true; } return; case EvqFragData: if (!mFragDataAdded) { Attribute info; const char kName[] = "gl_FragData"; info.name = kName; info.mappedName = kName; info.type = GL_FLOAT_VEC4; info.arraySize = static_cast<const TVariable *>( mSymbolTable.findBuiltIn("gl_MaxDrawBuffers", 100)) ->getConstPointer() ->getIConst(); info.precision = GL_MEDIUM_FLOAT; // Defined by spec. info.staticUse = true; mOutputVariables->push_back(info); mFragDataAdded = true; } return; case EvqFragDepthEXT: if (!mFragDepthEXTAdded) { Attribute info; const char kName[] = "gl_FragDepthEXT"; info.name = kName; info.mappedName = kName; info.type = GL_FLOAT; info.arraySize = 0; info.precision = GLVariablePrecision(static_cast<const TVariable *>( mSymbolTable.findBuiltIn("gl_FragDepthEXT", 100)) ->getType()); info.staticUse = true; mOutputVariables->push_back(info); mFragDepthEXTAdded = true; } return; case EvqFragDepth: if (!mFragDepthAdded) { Attribute info; const char kName[] = "gl_FragDepth"; info.name = kName; info.mappedName = kName; info.type = GL_FLOAT; info.arraySize = 0; info.precision = GL_HIGH_FLOAT; info.staticUse = true; mOutputVariables->push_back(info); mFragDepthAdded = true; } return; default: break; } } if (var) { var->staticUse = true; } }
// TODO(jmadill): This is not complete. void TOutputVulkanGLSL::writeLayoutQualifier(TIntermTyped *variable) { const TType &type = variable->getType(); bool needsCustomLayout = (type.getQualifier() == EvqAttribute || type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn || IsVarying(type.getQualifier()) || IsSampler(type.getBasicType()) || type.isInterfaceBlock()); if (!NeedsToWriteLayoutQualifier(type) && !needsCustomLayout) { return; } TInfoSinkBase &out = objSink(); const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier(); // This isn't super clean, but it gets the job done. // See corresponding code in GlslangWrapper.cpp. TIntermSymbol *symbol = variable->getAsSymbolNode(); ASSERT(symbol); ImmutableString name = symbol->getName(); const char *blockStorage = nullptr; const char *matrixPacking = nullptr; // For interface blocks, use the block name instead. When the layout qualifier is being // replaced in the backend, that would be the name that's available. if (type.isInterfaceBlock()) { const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock(); name = interfaceBlock->name(); TLayoutBlockStorage storage = interfaceBlock->blockStorage(); // Make sure block storage format is specified. if (storage != EbsStd430) { // Change interface block layout qualifiers to std140 for any layout that is not // explicitly set to std430. This is to comply with GL_KHR_vulkan_glsl where shared and // packed are not allowed (and std140 could be used instead) and unspecified layouts can // assume either std140 or std430 (and we choose std140 as std430 is not yet universally // supported). storage = EbsStd140; } blockStorage = getBlockStorageString(storage); } // Specify matrix packing if necessary. if (layoutQualifier.matrixPacking != EmpUnspecified) { matrixPacking = getMatrixPackingString(layoutQualifier.matrixPacking); } if (needsCustomLayout) { out << "@@ LAYOUT-" << name << "("; } else { out << "layout("; } // Output the list of qualifiers already known at this stage, i.e. everything other than // `location` and `set`/`binding`. std::string otherQualifiers = getCommonLayoutQualifiers(variable); const char *separator = ""; if (blockStorage) { out << separator << blockStorage; separator = ", "; } if (matrixPacking) { out << separator << matrixPacking; separator = ", "; } if (!otherQualifiers.empty()) { out << separator << otherQualifiers; } out << ") "; if (needsCustomLayout) { out << "@@"; } }