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/BuiltInFunctionEmulator.h" 8 #include "compiler/DetectCallDepth.h" 9 #include "compiler/ForLoopUnroll.h" 10 #include "compiler/Initialize.h" 11 #include "compiler/InitializeGLPosition.h" 12 #include "compiler/InitializeParseContext.h" 13 #include "compiler/MapLongVariableNames.h" 14 #include "compiler/ParseContext.h" 15 #include "compiler/RenameFunction.h" 16 #include "compiler/ShHandle.h" 17 #include "compiler/UnfoldShortCircuitAST.h" 18 #include "compiler/ValidateLimitations.h" 19 #include "compiler/VariablePacker.h" 20 #include "compiler/depgraph/DependencyGraph.h" 21 #include "compiler/depgraph/DependencyGraphOutput.h" 22 #include "compiler/timing/RestrictFragmentShaderTiming.h" 23 #include "compiler/timing/RestrictVertexShaderTiming.h" 24 #include "third_party/compiler/ArrayBoundsClamper.h" 25 26 bool isWebGLBasedSpec(ShShaderSpec spec) 27 { 28 return spec == SH_WEBGL_SPEC || spec == SH_CSS_SHADERS_SPEC; 29 } 30 31 namespace { 32 class TScopedPoolAllocator { 33 public: 34 TScopedPoolAllocator(TPoolAllocator* allocator) : mAllocator(allocator) { 35 mAllocator->push(); 36 SetGlobalPoolAllocator(mAllocator); 37 } 38 ~TScopedPoolAllocator() { 39 SetGlobalPoolAllocator(NULL); 40 mAllocator->pop(); 41 } 42 43 private: 44 TPoolAllocator* mAllocator; 45 }; 46 47 class TScopedSymbolTableLevel { 48 public: 49 TScopedSymbolTableLevel(TSymbolTable* table) : mTable(table) { 50 ASSERT(mTable->atBuiltInLevel()); 51 mTable->push(); 52 } 53 ~TScopedSymbolTableLevel() { 54 while (!mTable->atBuiltInLevel()) 55 mTable->pop(); 56 } 57 58 private: 59 TSymbolTable* mTable; 60 }; 61 } // namespace 62 63 TShHandleBase::TShHandleBase() { 64 allocator.push(); 65 SetGlobalPoolAllocator(&allocator); 66 } 67 68 TShHandleBase::~TShHandleBase() { 69 SetGlobalPoolAllocator(NULL); 70 allocator.popAll(); 71 } 72 73 TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec) 74 : shaderType(type), 75 shaderSpec(spec), 76 maxUniformVectors(0), 77 maxExpressionComplexity(0), 78 maxCallStackDepth(0), 79 fragmentPrecisionHigh(false), 80 clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC), 81 builtInFunctionEmulator(type) 82 { 83 longNameMap = LongNameMap::GetInstance(); 84 } 85 86 TCompiler::~TCompiler() 87 { 88 ASSERT(longNameMap); 89 longNameMap->Release(); 90 } 91 92 bool TCompiler::Init(const ShBuiltInResources& resources) 93 { 94 maxUniformVectors = (shaderType == SH_VERTEX_SHADER) ? 95 resources.MaxVertexUniformVectors : 96 resources.MaxFragmentUniformVectors; 97 maxExpressionComplexity = resources.MaxExpressionComplexity; 98 maxCallStackDepth = resources.MaxCallStackDepth; 99 100 SetGlobalPoolAllocator(&allocator); 101 102 // Generate built-in symbol table. 103 if (!InitBuiltInSymbolTable(resources)) 104 return false; 105 InitExtensionBehavior(resources, extensionBehavior); 106 fragmentPrecisionHigh = resources.FragmentPrecisionHigh == 1; 107 108 arrayBoundsClamper.SetClampingStrategy(resources.ArrayIndexClampingStrategy); 109 clampingStrategy = resources.ArrayIndexClampingStrategy; 110 111 hashFunction = resources.HashFunction; 112 113 return true; 114 } 115 116 bool TCompiler::compile(const char* const shaderStrings[], 117 size_t numStrings, 118 int compileOptions) 119 { 120 TScopedPoolAllocator scopedAlloc(&allocator); 121 clearResults(); 122 123 if (numStrings == 0) 124 return true; 125 126 // If compiling for WebGL, validate loop and indexing as well. 127 if (isWebGLBasedSpec(shaderSpec)) 128 compileOptions |= SH_VALIDATE_LOOP_INDEXING; 129 130 // First string is path of source file if flag is set. The actual source follows. 131 const char* sourcePath = NULL; 132 size_t firstSource = 0; 133 if (compileOptions & SH_SOURCE_PATH) 134 { 135 sourcePath = shaderStrings[0]; 136 ++firstSource; 137 } 138 139 TIntermediate intermediate(infoSink); 140 TParseContext parseContext(symbolTable, extensionBehavior, intermediate, 141 shaderType, shaderSpec, compileOptions, true, 142 sourcePath, infoSink); 143 parseContext.fragmentPrecisionHigh = fragmentPrecisionHigh; 144 SetGlobalParseContext(&parseContext); 145 146 // We preserve symbols at the built-in level from compile-to-compile. 147 // Start pushing the user-defined symbols at global level. 148 TScopedSymbolTableLevel scopedSymbolLevel(&symbolTable); 149 150 // Parse shader. 151 bool success = 152 (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) && 153 (parseContext.treeRoot != NULL); 154 if (success) { 155 TIntermNode* root = parseContext.treeRoot; 156 success = intermediate.postProcess(root); 157 158 if (success) 159 success = detectCallDepth(root, infoSink, (compileOptions & SH_LIMIT_CALL_STACK_DEPTH) != 0); 160 161 if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING)) 162 success = validateLimitations(root); 163 164 if (success && (compileOptions & SH_TIMING_RESTRICTIONS)) 165 success = enforceTimingRestrictions(root, (compileOptions & SH_DEPENDENCY_GRAPH) != 0); 166 167 if (success && shaderSpec == SH_CSS_SHADERS_SPEC) 168 rewriteCSSShader(root); 169 170 // Unroll for-loop markup needs to happen after validateLimitations pass. 171 if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX)) 172 ForLoopUnroll::MarkForLoopsWithIntegerIndicesForUnrolling(root); 173 174 // Built-in function emulation needs to happen after validateLimitations pass. 175 if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS)) 176 builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root); 177 178 // Clamping uniform array bounds needs to happen after validateLimitations pass. 179 if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS)) 180 arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root); 181 182 // Disallow expressions deemed too complex. 183 if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY)) 184 success = limitExpressionComplexity(root); 185 186 // Call mapLongVariableNames() before collectAttribsUniforms() so in 187 // collectAttribsUniforms() we already have the mapped symbol names and 188 // we could composite mapped and original variable names. 189 // Also, if we hash all the names, then no need to do this for long names. 190 if (success && (compileOptions & SH_MAP_LONG_VARIABLE_NAMES) && hashFunction == NULL) 191 mapLongVariableNames(root); 192 193 if (success && shaderType == SH_VERTEX_SHADER && (compileOptions & SH_INIT_GL_POSITION)) { 194 InitializeGLPosition initGLPosition; 195 root->traverse(&initGLPosition); 196 } 197 198 if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT)) { 199 UnfoldShortCircuitAST unfoldShortCircuit; 200 root->traverse(&unfoldShortCircuit); 201 unfoldShortCircuit.updateTree(); 202 } 203 204 if (success && (compileOptions & SH_VARIABLES)) { 205 collectVariables(root); 206 if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS) { 207 success = enforcePackingRestrictions(); 208 if (!success) { 209 infoSink.info.prefix(EPrefixError); 210 infoSink.info << "too many uniforms"; 211 } 212 } 213 } 214 215 if (success && (compileOptions & SH_INTERMEDIATE_TREE)) 216 intermediate.outputTree(root); 217 218 if (success && (compileOptions & SH_OBJECT_CODE)) 219 translate(root); 220 } 221 222 // Cleanup memory. 223 intermediate.remove(parseContext.treeRoot); 224 225 return success; 226 } 227 228 bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources) 229 { 230 compileResources = resources; 231 232 assert(symbolTable.isEmpty()); 233 symbolTable.push(); 234 235 TPublicType integer; 236 integer.type = EbtInt; 237 integer.size = 1; 238 integer.matrix = false; 239 integer.array = false; 240 241 TPublicType floatingPoint; 242 floatingPoint.type = EbtFloat; 243 floatingPoint.size = 1; 244 floatingPoint.matrix = false; 245 floatingPoint.array = false; 246 247 TPublicType sampler; 248 sampler.size = 1; 249 sampler.matrix = false; 250 sampler.array = false; 251 252 switch(shaderType) 253 { 254 case SH_FRAGMENT_SHADER: 255 symbolTable.setDefaultPrecision(integer, EbpMedium); 256 break; 257 case SH_VERTEX_SHADER: 258 symbolTable.setDefaultPrecision(integer, EbpHigh); 259 symbolTable.setDefaultPrecision(floatingPoint, EbpHigh); 260 break; 261 default: assert(false && "Language not supported"); 262 } 263 // We set defaults for all the sampler types, even those that are 264 // only available if an extension exists. 265 for (int samplerType = EbtGuardSamplerBegin + 1; 266 samplerType < EbtGuardSamplerEnd; ++samplerType) { 267 sampler.type = static_cast<TBasicType>(samplerType); 268 symbolTable.setDefaultPrecision(sampler, EbpLow); 269 } 270 271 InsertBuiltInFunctions(shaderType, shaderSpec, resources, symbolTable); 272 273 IdentifyBuiltIns(shaderType, shaderSpec, resources, symbolTable); 274 275 return true; 276 } 277 278 void TCompiler::clearResults() 279 { 280 arrayBoundsClamper.Cleanup(); 281 infoSink.info.erase(); 282 infoSink.obj.erase(); 283 infoSink.debug.erase(); 284 285 attribs.clear(); 286 uniforms.clear(); 287 varyings.clear(); 288 289 builtInFunctionEmulator.Cleanup(); 290 291 nameMap.clear(); 292 } 293 294 bool TCompiler::detectCallDepth(TIntermNode* root, TInfoSink& infoSink, bool limitCallStackDepth) 295 { 296 DetectCallDepth detect(infoSink, limitCallStackDepth, maxCallStackDepth); 297 root->traverse(&detect); 298 switch (detect.detectCallDepth()) { 299 case DetectCallDepth::kErrorNone: 300 return true; 301 case DetectCallDepth::kErrorMissingMain: 302 infoSink.info.prefix(EPrefixError); 303 infoSink.info << "Missing main()"; 304 return false; 305 case DetectCallDepth::kErrorRecursion: 306 infoSink.info.prefix(EPrefixError); 307 infoSink.info << "Function recursion detected"; 308 return false; 309 case DetectCallDepth::kErrorMaxDepthExceeded: 310 infoSink.info.prefix(EPrefixError); 311 infoSink.info << "Function call stack too deep"; 312 return false; 313 default: 314 UNREACHABLE(); 315 return false; 316 } 317 } 318 319 void TCompiler::rewriteCSSShader(TIntermNode* root) 320 { 321 RenameFunction renamer("main(", "css_main("); 322 root->traverse(&renamer); 323 } 324 325 bool TCompiler::validateLimitations(TIntermNode* root) { 326 ValidateLimitations validate(shaderType, infoSink.info); 327 root->traverse(&validate); 328 return validate.numErrors() == 0; 329 } 330 331 bool TCompiler::enforceTimingRestrictions(TIntermNode* root, bool outputGraph) 332 { 333 if (shaderSpec != SH_WEBGL_SPEC) { 334 infoSink.info << "Timing restrictions must be enforced under the WebGL spec."; 335 return false; 336 } 337 338 if (shaderType == SH_FRAGMENT_SHADER) { 339 TDependencyGraph graph(root); 340 341 // Output any errors first. 342 bool success = enforceFragmentShaderTimingRestrictions(graph); 343 344 // Then, output the dependency graph. 345 if (outputGraph) { 346 TDependencyGraphOutput output(infoSink.info); 347 output.outputAllSpanningTrees(graph); 348 } 349 350 return success; 351 } 352 else { 353 return enforceVertexShaderTimingRestrictions(root); 354 } 355 } 356 357 bool TCompiler::limitExpressionComplexity(TIntermNode* root) 358 { 359 TIntermTraverser traverser; 360 root->traverse(&traverser); 361 TDependencyGraph graph(root); 362 363 for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls(); 364 iter != graph.endUserDefinedFunctionCalls(); 365 ++iter) 366 { 367 TGraphFunctionCall* samplerSymbol = *iter; 368 TDependencyGraphTraverser graphTraverser; 369 samplerSymbol->traverse(&graphTraverser); 370 } 371 372 if (traverser.getMaxDepth() > maxExpressionComplexity) { 373 infoSink.info << "Expression too complex."; 374 return false; 375 } 376 return true; 377 } 378 379 bool TCompiler::enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph) 380 { 381 RestrictFragmentShaderTiming restrictor(infoSink.info); 382 restrictor.enforceRestrictions(graph); 383 return restrictor.numErrors() == 0; 384 } 385 386 bool TCompiler::enforceVertexShaderTimingRestrictions(TIntermNode* root) 387 { 388 RestrictVertexShaderTiming restrictor(infoSink.info); 389 restrictor.enforceRestrictions(root); 390 return restrictor.numErrors() == 0; 391 } 392 393 void TCompiler::collectVariables(TIntermNode* root) 394 { 395 CollectVariables collect(attribs, uniforms, varyings, hashFunction); 396 root->traverse(&collect); 397 } 398 399 bool TCompiler::enforcePackingRestrictions() 400 { 401 VariablePacker packer; 402 return packer.CheckVariablesWithinPackingLimits(maxUniformVectors, uniforms); 403 } 404 405 void TCompiler::mapLongVariableNames(TIntermNode* root) 406 { 407 ASSERT(longNameMap); 408 MapLongVariableNames map(longNameMap); 409 root->traverse(&map); 410 } 411 412 int TCompiler::getMappedNameMaxLength() const 413 { 414 return MAX_SHORTENED_IDENTIFIER_SIZE + 1; 415 } 416 417 const TExtensionBehavior& TCompiler::getExtensionBehavior() const 418 { 419 return extensionBehavior; 420 } 421 422 const ShBuiltInResources& TCompiler::getResources() const 423 { 424 return compileResources; 425 } 426 427 const ArrayBoundsClamper& TCompiler::getArrayBoundsClamper() const 428 { 429 return arrayBoundsClamper; 430 } 431 432 ShArrayIndexClampingStrategy TCompiler::getArrayIndexClampingStrategy() const 433 { 434 return clampingStrategy; 435 } 436 437 const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const 438 { 439 return builtInFunctionEmulator; 440 } 441