1 // 2 // Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 #include "angle_gl.h" 8 #include "compiler/translator/VariableInfo.h" 9 #include "compiler/translator/util.h" 10 #include "common/utilities.h" 11 12 namespace sh 13 { 14 15 namespace 16 { 17 18 TString InterfaceBlockFieldName(const TInterfaceBlock &interfaceBlock, const TField &field) 19 { 20 if (interfaceBlock.hasInstanceName()) 21 { 22 return interfaceBlock.name() + "." + field.name(); 23 } 24 else 25 { 26 return field.name(); 27 } 28 } 29 30 BlockLayoutType GetBlockLayoutType(TLayoutBlockStorage blockStorage) 31 { 32 switch (blockStorage) 33 { 34 case EbsPacked: return BLOCKLAYOUT_PACKED; 35 case EbsShared: return BLOCKLAYOUT_SHARED; 36 case EbsStd140: return BLOCKLAYOUT_STANDARD; 37 default: UNREACHABLE(); return BLOCKLAYOUT_SHARED; 38 } 39 } 40 41 void ExpandUserDefinedVariable(const ShaderVariable &variable, 42 const std::string &name, 43 const std::string &mappedName, 44 bool markStaticUse, 45 std::vector<ShaderVariable> *expanded); 46 47 void ExpandVariable(const ShaderVariable &variable, 48 const std::string &name, 49 const std::string &mappedName, 50 bool markStaticUse, 51 std::vector<ShaderVariable> *expanded) 52 { 53 if (variable.isStruct()) 54 { 55 if (variable.isArray()) 56 { 57 for (size_t elementIndex = 0; elementIndex < variable.elementCount(); elementIndex++) 58 { 59 std::string lname = name + ::ArrayString(elementIndex); 60 std::string lmappedName = mappedName + ::ArrayString(elementIndex); 61 ExpandUserDefinedVariable(variable, lname, lmappedName, markStaticUse, expanded); 62 } 63 } 64 else 65 { 66 ExpandUserDefinedVariable(variable, name, mappedName, markStaticUse, expanded); 67 } 68 } 69 else 70 { 71 ShaderVariable expandedVar = variable; 72 73 expandedVar.name = name; 74 expandedVar.mappedName = mappedName; 75 76 // Mark all expanded fields as used if the parent is used 77 if (markStaticUse) 78 { 79 expandedVar.staticUse = true; 80 } 81 82 if (expandedVar.isArray()) 83 { 84 expandedVar.name += "[0]"; 85 expandedVar.mappedName += "[0]"; 86 } 87 88 expanded->push_back(expandedVar); 89 } 90 } 91 92 void ExpandUserDefinedVariable(const ShaderVariable &variable, 93 const std::string &name, 94 const std::string &mappedName, 95 bool markStaticUse, 96 std::vector<ShaderVariable> *expanded) 97 { 98 ASSERT(variable.isStruct()); 99 100 const std::vector<ShaderVariable> &fields = variable.fields; 101 102 for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++) 103 { 104 const ShaderVariable &field = fields[fieldIndex]; 105 ExpandVariable(field, 106 name + "." + field.name, 107 mappedName + "." + field.mappedName, 108 markStaticUse, 109 expanded); 110 } 111 } 112 113 template <class VarT> 114 VarT *FindVariable(const TString &name, 115 std::vector<VarT> *infoList) 116 { 117 // TODO(zmo): optimize this function. 118 for (size_t ii = 0; ii < infoList->size(); ++ii) 119 { 120 if ((*infoList)[ii].name.c_str() == name) 121 return &((*infoList)[ii]); 122 } 123 124 return NULL; 125 } 126 127 } 128 129 CollectVariables::CollectVariables(std::vector<sh::Attribute> *attribs, 130 std::vector<sh::Attribute> *outputVariables, 131 std::vector<sh::Uniform> *uniforms, 132 std::vector<sh::Varying> *varyings, 133 std::vector<sh::InterfaceBlock> *interfaceBlocks, 134 ShHashFunction64 hashFunction) 135 : mAttribs(attribs), 136 mOutputVariables(outputVariables), 137 mUniforms(uniforms), 138 mVaryings(varyings), 139 mInterfaceBlocks(interfaceBlocks), 140 mPointCoordAdded(false), 141 mFrontFacingAdded(false), 142 mFragCoordAdded(false), 143 mHashFunction(hashFunction) 144 { 145 } 146 147 // We want to check whether a uniform/varying is statically used 148 // because we only count the used ones in packing computing. 149 // Also, gl_FragCoord, gl_PointCoord, and gl_FrontFacing count 150 // toward varying counting if they are statically used in a fragment 151 // shader. 152 void CollectVariables::visitSymbol(TIntermSymbol *symbol) 153 { 154 ASSERT(symbol != NULL); 155 ShaderVariable *var = NULL; 156 const TString &symbolName = symbol->getSymbol(); 157 158 if (IsVarying(symbol->getQualifier())) 159 { 160 var = FindVariable(symbolName, mVaryings); 161 } 162 else if (symbol->getType().getBasicType() == EbtInterfaceBlock) 163 { 164 UNREACHABLE(); 165 } 166 else 167 { 168 switch (symbol->getQualifier()) 169 { 170 case EvqAttribute: 171 case EvqVertexIn: 172 var = FindVariable(symbolName, mAttribs); 173 break; 174 case EvqFragmentOut: 175 var = FindVariable(symbolName, mOutputVariables); 176 break; 177 case EvqUniform: 178 { 179 const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock(); 180 if (interfaceBlock) 181 { 182 InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), mInterfaceBlocks); 183 ASSERT(namedBlock); 184 var = FindVariable(symbolName, &namedBlock->fields); 185 186 // Set static use on the parent interface block here 187 namedBlock->staticUse = true; 188 189 } 190 else 191 { 192 var = FindVariable(symbolName, mUniforms); 193 } 194 195 // It's an internal error to reference an undefined user uniform 196 ASSERT(symbolName.compare(0, 3, "gl_") == 0 || var); 197 } 198 break; 199 case EvqFragCoord: 200 if (!mFragCoordAdded) 201 { 202 Varying info; 203 info.name = "gl_FragCoord"; 204 info.mappedName = "gl_FragCoord"; 205 info.type = GL_FLOAT_VEC4; 206 info.arraySize = 0; 207 info.precision = GL_MEDIUM_FLOAT; // Use mediump as it doesn't really matter. 208 info.staticUse = true; 209 mVaryings->push_back(info); 210 mFragCoordAdded = true; 211 } 212 return; 213 case EvqFrontFacing: 214 if (!mFrontFacingAdded) 215 { 216 Varying info; 217 info.name = "gl_FrontFacing"; 218 info.mappedName = "gl_FrontFacing"; 219 info.type = GL_BOOL; 220 info.arraySize = 0; 221 info.precision = GL_NONE; 222 info.staticUse = true; 223 mVaryings->push_back(info); 224 mFrontFacingAdded = true; 225 } 226 return; 227 case EvqPointCoord: 228 if (!mPointCoordAdded) 229 { 230 Varying info; 231 info.name = "gl_PointCoord"; 232 info.mappedName = "gl_PointCoord"; 233 info.type = GL_FLOAT_VEC2; 234 info.arraySize = 0; 235 info.precision = GL_MEDIUM_FLOAT; // Use mediump as it doesn't really matter. 236 info.staticUse = true; 237 mVaryings->push_back(info); 238 mPointCoordAdded = true; 239 } 240 return; 241 default: 242 break; 243 } 244 } 245 if (var) 246 { 247 var->staticUse = true; 248 } 249 } 250 251 class NameHashingTraverser : public GetVariableTraverser 252 { 253 public: 254 NameHashingTraverser(ShHashFunction64 hashFunction) 255 : mHashFunction(hashFunction) 256 {} 257 258 private: 259 DISALLOW_COPY_AND_ASSIGN(NameHashingTraverser); 260 261 virtual void visitVariable(ShaderVariable *variable) 262 { 263 TString stringName = TString(variable->name.c_str()); 264 variable->mappedName = TIntermTraverser::hash(stringName, mHashFunction).c_str(); 265 } 266 267 ShHashFunction64 mHashFunction; 268 }; 269 270 // Attributes, which cannot have struct fields, are a special case 271 template <> 272 void CollectVariables::visitVariable(const TIntermSymbol *variable, 273 std::vector<Attribute> *infoList) const 274 { 275 ASSERT(variable); 276 const TType &type = variable->getType(); 277 ASSERT(!type.getStruct()); 278 279 Attribute attribute; 280 281 attribute.type = GLVariableType(type); 282 attribute.precision = GLVariablePrecision(type); 283 attribute.name = variable->getSymbol().c_str(); 284 attribute.arraySize = static_cast<unsigned int>(type.getArraySize()); 285 attribute.mappedName = TIntermTraverser::hash(variable->getSymbol(), mHashFunction).c_str(); 286 attribute.location = variable->getType().getLayoutQualifier().location; 287 288 infoList->push_back(attribute); 289 } 290 291 template <> 292 void CollectVariables::visitVariable(const TIntermSymbol *variable, 293 std::vector<InterfaceBlock> *infoList) const 294 { 295 InterfaceBlock interfaceBlock; 296 const TInterfaceBlock *blockType = variable->getType().getInterfaceBlock(); 297 ASSERT(blockType); 298 299 interfaceBlock.name = blockType->name().c_str(); 300 interfaceBlock.mappedName = TIntermTraverser::hash(variable->getSymbol(), mHashFunction).c_str(); 301 interfaceBlock.instanceName = (blockType->hasInstanceName() ? blockType->instanceName().c_str() : ""); 302 interfaceBlock.arraySize = variable->getArraySize(); 303 interfaceBlock.isRowMajorLayout = (blockType->matrixPacking() == EmpRowMajor); 304 interfaceBlock.layout = GetBlockLayoutType(blockType->blockStorage()); 305 306 // Gather field information 307 const TFieldList &fieldList = blockType->fields(); 308 309 for (size_t fieldIndex = 0; fieldIndex < fieldList.size(); ++fieldIndex) 310 { 311 const TField &field = *fieldList[fieldIndex]; 312 const TString &fullFieldName = InterfaceBlockFieldName(*blockType, field); 313 const TType &fieldType = *field.type(); 314 315 GetVariableTraverser traverser; 316 traverser.traverse(fieldType, fullFieldName, &interfaceBlock.fields); 317 318 interfaceBlock.fields.back().isRowMajorLayout = (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor); 319 } 320 321 infoList->push_back(interfaceBlock); 322 } 323 324 template <typename VarT> 325 void CollectVariables::visitVariable(const TIntermSymbol *variable, 326 std::vector<VarT> *infoList) const 327 { 328 NameHashingTraverser traverser(mHashFunction); 329 traverser.traverse(variable->getType(), variable->getSymbol(), infoList); 330 } 331 332 template <typename VarT> 333 void CollectVariables::visitInfoList(const TIntermSequence &sequence, 334 std::vector<VarT> *infoList) const 335 { 336 for (size_t seqIndex = 0; seqIndex < sequence.size(); seqIndex++) 337 { 338 const TIntermSymbol *variable = sequence[seqIndex]->getAsSymbolNode(); 339 // The only case in which the sequence will not contain a 340 // TIntermSymbol node is initialization. It will contain a 341 // TInterBinary node in that case. Since attributes, uniforms, 342 // and varyings cannot be initialized in a shader, we must have 343 // only TIntermSymbol nodes in the sequence. 344 ASSERT(variable != NULL); 345 visitVariable(variable, infoList); 346 } 347 } 348 349 bool CollectVariables::visitAggregate(Visit, TIntermAggregate *node) 350 { 351 bool visitChildren = true; 352 353 switch (node->getOp()) 354 { 355 case EOpDeclaration: 356 { 357 const TIntermSequence &sequence = *(node->getSequence()); 358 ASSERT(!sequence.empty()); 359 360 const TIntermTyped &typedNode = *(sequence.front()->getAsTyped()); 361 TQualifier qualifier = typedNode.getQualifier(); 362 363 if (typedNode.getBasicType() == EbtInterfaceBlock) 364 { 365 visitInfoList(sequence, mInterfaceBlocks); 366 visitChildren = false; 367 } 368 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn || 369 qualifier == EvqFragmentOut || qualifier == EvqUniform || 370 IsVarying(qualifier)) 371 { 372 switch (qualifier) 373 { 374 case EvqAttribute: 375 case EvqVertexIn: 376 visitInfoList(sequence, mAttribs); 377 break; 378 case EvqFragmentOut: 379 visitInfoList(sequence, mOutputVariables); 380 break; 381 case EvqUniform: 382 visitInfoList(sequence, mUniforms); 383 break; 384 default: 385 visitInfoList(sequence, mVaryings); 386 break; 387 } 388 389 visitChildren = false; 390 } 391 break; 392 } 393 default: break; 394 } 395 396 return visitChildren; 397 } 398 399 bool CollectVariables::visitBinary(Visit, TIntermBinary *binaryNode) 400 { 401 if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock) 402 { 403 // NOTE: we do not determine static use for individual blocks of an array 404 TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped(); 405 ASSERT(blockNode); 406 407 TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion(); 408 ASSERT(constantUnion); 409 410 const TInterfaceBlock *interfaceBlock = blockNode->getType().getInterfaceBlock(); 411 InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), mInterfaceBlocks); 412 ASSERT(namedBlock); 413 namedBlock->staticUse = true; 414 415 unsigned int fieldIndex = constantUnion->getUConst(0); 416 ASSERT(fieldIndex < namedBlock->fields.size()); 417 namedBlock->fields[fieldIndex].staticUse = true; 418 return false; 419 } 420 421 return true; 422 } 423 424 template <typename VarT> 425 void ExpandVariables(const std::vector<VarT> &compact, 426 std::vector<ShaderVariable> *expanded) 427 { 428 for (size_t variableIndex = 0; variableIndex < compact.size(); variableIndex++) 429 { 430 const ShaderVariable &variable = compact[variableIndex]; 431 ExpandVariable(variable, variable.name, variable.mappedName, variable.staticUse, expanded); 432 } 433 } 434 435 template void ExpandVariables(const std::vector<Uniform> &, std::vector<ShaderVariable> *); 436 template void ExpandVariables(const std::vector<Varying> &, std::vector<ShaderVariable> *); 437 438 } 439