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 "compiler/translator/VariableInfo.h" 8 9 namespace { 10 11 TString arrayBrackets(int index) 12 { 13 TStringStream stream; 14 stream << "[" << index << "]"; 15 return stream.str(); 16 } 17 18 // Returns the data type for an attribute, uniform, or varying. 19 ShDataType getVariableDataType(const TType& type) 20 { 21 switch (type.getBasicType()) { 22 case EbtFloat: 23 if (type.isMatrix()) { 24 switch (type.getCols()) 25 { 26 case 2: 27 switch (type.getRows()) 28 { 29 case 2: return SH_FLOAT_MAT2; 30 case 3: return SH_FLOAT_MAT2x3; 31 case 4: return SH_FLOAT_MAT2x4; 32 default: UNREACHABLE(); 33 } 34 case 3: 35 switch (type.getRows()) 36 { 37 case 2: return SH_FLOAT_MAT3x2; 38 case 3: return SH_FLOAT_MAT3; 39 case 4: return SH_FLOAT_MAT3x4; 40 default: UNREACHABLE(); 41 } 42 case 4: 43 switch (type.getRows()) 44 { 45 case 2: return SH_FLOAT_MAT4x2; 46 case 3: return SH_FLOAT_MAT4x3; 47 case 4: return SH_FLOAT_MAT4; 48 default: UNREACHABLE(); 49 } 50 } 51 } else if (type.isVector()) { 52 switch (type.getNominalSize()) { 53 case 2: return SH_FLOAT_VEC2; 54 case 3: return SH_FLOAT_VEC3; 55 case 4: return SH_FLOAT_VEC4; 56 default: UNREACHABLE(); 57 } 58 } else { 59 return SH_FLOAT; 60 } 61 case EbtInt: 62 if (type.isMatrix()) { 63 UNREACHABLE(); 64 } else if (type.isVector()) { 65 switch (type.getNominalSize()) { 66 case 2: return SH_INT_VEC2; 67 case 3: return SH_INT_VEC3; 68 case 4: return SH_INT_VEC4; 69 default: UNREACHABLE(); 70 } 71 } else { 72 return SH_INT; 73 } 74 case EbtUInt: 75 if (type.isMatrix()) { 76 UNREACHABLE(); 77 } else if (type.isVector()) { 78 switch (type.getNominalSize()) { 79 case 2: return SH_UNSIGNED_INT_VEC2; 80 case 3: return SH_UNSIGNED_INT_VEC3; 81 case 4: return SH_UNSIGNED_INT_VEC4; 82 default: UNREACHABLE(); 83 } 84 } else { 85 return SH_UNSIGNED_INT; 86 } 87 case EbtBool: 88 if (type.isMatrix()) { 89 UNREACHABLE(); 90 } else if (type.isVector()) { 91 switch (type.getNominalSize()) { 92 case 2: return SH_BOOL_VEC2; 93 case 3: return SH_BOOL_VEC3; 94 case 4: return SH_BOOL_VEC4; 95 default: UNREACHABLE(); 96 } 97 } else { 98 return SH_BOOL; 99 } 100 case EbtSampler2D: return SH_SAMPLER_2D; 101 case EbtSampler3D: return SH_SAMPLER_3D; 102 case EbtSamplerCube: return SH_SAMPLER_CUBE; 103 case EbtSamplerExternalOES: return SH_SAMPLER_EXTERNAL_OES; 104 case EbtSampler2DRect: return SH_SAMPLER_2D_RECT_ARB; 105 case EbtSampler2DArray: return SH_SAMPLER_2D_ARRAY; 106 case EbtISampler2D: return SH_INT_SAMPLER_2D; 107 case EbtISampler3D: return SH_INT_SAMPLER_3D; 108 case EbtISamplerCube: return SH_INT_SAMPLER_CUBE; 109 case EbtISampler2DArray: return SH_INT_SAMPLER_2D_ARRAY; 110 case EbtUSampler2D: return SH_UNSIGNED_INT_SAMPLER_2D; 111 case EbtUSampler3D: return SH_UNSIGNED_INT_SAMPLER_3D; 112 case EbtUSamplerCube: return SH_UNSIGNED_INT_SAMPLER_CUBE; 113 case EbtUSampler2DArray: return SH_UNSIGNED_INT_SAMPLER_2D_ARRAY; 114 case EbtSampler2DShadow: return SH_SAMPLER_2D_SHADOW; 115 case EbtSamplerCubeShadow: return SH_SAMPLER_CUBE_SHADOW; 116 case EbtSampler2DArrayShadow: return SH_SAMPLER_2D_ARRAY_SHADOW; 117 default: UNREACHABLE(); 118 } 119 return SH_NONE; 120 } 121 122 void getBuiltInVariableInfo(const TType& type, 123 const TString& name, 124 const TString& mappedName, 125 TVariableInfoList& infoList); 126 void getUserDefinedVariableInfo(const TType& type, 127 const TString& name, 128 const TString& mappedName, 129 TVariableInfoList& infoList, 130 ShHashFunction64 hashFunction); 131 132 // Returns info for an attribute, uniform, or varying. 133 void getVariableInfo(const TType& type, 134 const TString& name, 135 const TString& mappedName, 136 TVariableInfoList& infoList, 137 ShHashFunction64 hashFunction) 138 { 139 if (type.getBasicType() == EbtStruct || type.isInterfaceBlock()) { 140 if (type.isArray()) { 141 for (int i = 0; i < type.getArraySize(); ++i) { 142 TString lname = name + arrayBrackets(i); 143 TString lmappedName = mappedName + arrayBrackets(i); 144 getUserDefinedVariableInfo(type, lname, lmappedName, infoList, hashFunction); 145 } 146 } else { 147 getUserDefinedVariableInfo(type, name, mappedName, infoList, hashFunction); 148 } 149 } else { 150 getBuiltInVariableInfo(type, name, mappedName, infoList); 151 } 152 } 153 154 void getBuiltInVariableInfo(const TType& type, 155 const TString& name, 156 const TString& mappedName, 157 TVariableInfoList& infoList) 158 { 159 ASSERT(type.getBasicType() != EbtStruct); 160 161 TVariableInfo varInfo; 162 if (type.isArray()) { 163 varInfo.name = (name + "[0]").c_str(); 164 varInfo.mappedName = (mappedName + "[0]").c_str(); 165 varInfo.size = type.getArraySize(); 166 varInfo.isArray = true; 167 } else { 168 varInfo.name = name.c_str(); 169 varInfo.mappedName = mappedName.c_str(); 170 varInfo.size = 1; 171 varInfo.isArray = false; 172 } 173 varInfo.precision = type.getPrecision(); 174 varInfo.type = getVariableDataType(type); 175 infoList.push_back(varInfo); 176 } 177 178 void getUserDefinedVariableInfo(const TType& type, 179 const TString& name, 180 const TString& mappedName, 181 TVariableInfoList& infoList, 182 ShHashFunction64 hashFunction) 183 { 184 ASSERT(type.getBasicType() == EbtStruct || type.isInterfaceBlock()); 185 186 const TFieldList& fields = type.isInterfaceBlock() ? 187 type.getInterfaceBlock()->fields() : 188 type.getStruct()->fields(); 189 for (size_t i = 0; i < fields.size(); ++i) { 190 const TType& fieldType = *(fields[i]->type()); 191 const TString& fieldName = fields[i]->name(); 192 getVariableInfo(fieldType, 193 name + "." + fieldName, 194 mappedName + "." + TIntermTraverser::hash(fieldName, hashFunction), 195 infoList, 196 hashFunction); 197 } 198 } 199 200 TVariableInfo* findVariable(const TType& type, 201 const TString& name, 202 TVariableInfoList& infoList) 203 { 204 // TODO(zmo): optimize this function. 205 TString myName = name; 206 if (type.isArray()) 207 myName += "[0]"; 208 for (size_t ii = 0; ii < infoList.size(); ++ii) 209 { 210 if (infoList[ii].name.c_str() == myName) 211 return &(infoList[ii]); 212 } 213 return NULL; 214 } 215 216 } // namespace anonymous 217 218 TVariableInfo::TVariableInfo() 219 : type(SH_NONE), 220 size(0), 221 isArray(false), 222 precision(EbpUndefined), 223 staticUse(false) 224 { 225 } 226 227 TVariableInfo::TVariableInfo(ShDataType type, int size) 228 : type(type), 229 size(size), 230 isArray(false), 231 precision(EbpUndefined), 232 staticUse(false) 233 { 234 } 235 236 CollectVariables::CollectVariables(TVariableInfoList& attribs, 237 TVariableInfoList& uniforms, 238 TVariableInfoList& varyings, 239 ShHashFunction64 hashFunction) 240 : mAttribs(attribs), 241 mUniforms(uniforms), 242 mVaryings(varyings), 243 mPointCoordAdded(false), 244 mFrontFacingAdded(false), 245 mFragCoordAdded(false), 246 mHashFunction(hashFunction) 247 { 248 } 249 250 // We want to check whether a uniform/varying is statically used 251 // because we only count the used ones in packing computing. 252 // Also, gl_FragCoord, gl_PointCoord, and gl_FrontFacing count 253 // toward varying counting if they are statically used in a fragment 254 // shader. 255 void CollectVariables::visitSymbol(TIntermSymbol* symbol) 256 { 257 ASSERT(symbol != NULL); 258 TVariableInfo* var = NULL; 259 switch (symbol->getQualifier()) 260 { 261 case EvqVaryingOut: 262 case EvqInvariantVaryingOut: 263 case EvqVaryingIn: 264 case EvqInvariantVaryingIn: 265 var = findVariable(symbol->getType(), symbol->getSymbol(), mVaryings); 266 break; 267 case EvqUniform: 268 var = findVariable(symbol->getType(), symbol->getSymbol(), mUniforms); 269 break; 270 case EvqFragCoord: 271 if (!mFragCoordAdded) { 272 TVariableInfo info; 273 info.name = "gl_FragCoord"; 274 info.mappedName = "gl_FragCoord"; 275 info.type = SH_FLOAT_VEC4; 276 info.size = 1; 277 info.precision = EbpMedium; // Use mediump as it doesn't really matter. 278 info.staticUse = true; 279 mVaryings.push_back(info); 280 mFragCoordAdded = true; 281 } 282 return; 283 case EvqFrontFacing: 284 if (!mFrontFacingAdded) { 285 TVariableInfo info; 286 info.name = "gl_FrontFacing"; 287 info.mappedName = "gl_FrontFacing"; 288 info.type = SH_BOOL; 289 info.size = 1; 290 info.precision = EbpUndefined; 291 info.staticUse = true; 292 mVaryings.push_back(info); 293 mFrontFacingAdded = true; 294 } 295 return; 296 case EvqPointCoord: 297 if (!mPointCoordAdded) { 298 TVariableInfo info; 299 info.name = "gl_PointCoord"; 300 info.mappedName = "gl_PointCoord"; 301 info.type = SH_FLOAT_VEC2; 302 info.size = 1; 303 info.precision = EbpMedium; // Use mediump as it doesn't really matter. 304 info.staticUse = true; 305 mVaryings.push_back(info); 306 mPointCoordAdded = true; 307 } 308 return; 309 default: 310 break; 311 } 312 if (var) 313 var->staticUse = true; 314 } 315 316 bool CollectVariables::visitAggregate(Visit, TIntermAggregate* node) 317 { 318 bool visitChildren = true; 319 320 switch (node->getOp()) 321 { 322 case EOpDeclaration: { 323 const TIntermSequence& sequence = node->getSequence(); 324 TQualifier qualifier = sequence.front()->getAsTyped()->getQualifier(); 325 if (qualifier == EvqAttribute || qualifier == EvqVertexIn || qualifier == EvqUniform || 326 qualifier == EvqVaryingIn || qualifier == EvqVaryingOut || 327 qualifier == EvqInvariantVaryingIn || qualifier == EvqInvariantVaryingOut) 328 { 329 TVariableInfoList *infoList = NULL; 330 331 switch (qualifier) 332 { 333 case EvqAttribute: 334 case EvqVertexIn: 335 infoList = &mAttribs; 336 break; 337 case EvqUniform: 338 infoList = &mUniforms; 339 break; 340 default: 341 infoList = &mVaryings; 342 break; 343 } 344 345 for (TIntermSequence::const_iterator i = sequence.begin(); 346 i != sequence.end(); ++i) 347 { 348 const TIntermSymbol* variable = (*i)->getAsSymbolNode(); 349 // The only case in which the sequence will not contain a 350 // TIntermSymbol node is initialization. It will contain a 351 // TInterBinary node in that case. Since attributes, uniforms, 352 // and varyings cannot be initialized in a shader, we must have 353 // only TIntermSymbol nodes in the sequence. 354 ASSERT(variable != NULL); 355 TString processedSymbol; 356 if (mHashFunction == NULL) 357 processedSymbol = variable->getSymbol(); 358 else 359 processedSymbol = TIntermTraverser::hash(variable->getSymbol(), mHashFunction); 360 getVariableInfo(variable->getType(), 361 variable->getSymbol(), 362 processedSymbol, 363 *infoList, 364 mHashFunction); 365 visitChildren = false; 366 } 367 } 368 break; 369 } 370 default: break; 371 } 372 373 return visitChildren; 374 } 375