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 26bool isWebGLBasedSpec(ShShaderSpec spec) 27{ 28 return spec == SH_WEBGL_SPEC || spec == SH_CSS_SHADERS_SPEC; 29} 30 31namespace { 32class TScopedPoolAllocator { 33public: 34 TScopedPoolAllocator(TPoolAllocator* allocator) : mAllocator(allocator) { 35 mAllocator->push(); 36 SetGlobalPoolAllocator(mAllocator); 37 } 38 ~TScopedPoolAllocator() { 39 SetGlobalPoolAllocator(NULL); 40 mAllocator->pop(); 41 } 42 43private: 44 TPoolAllocator* mAllocator; 45}; 46 47class TScopedSymbolTableLevel { 48public: 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 58private: 59 TSymbolTable* mTable; 60}; 61} // namespace 62 63TShHandleBase::TShHandleBase() { 64 allocator.push(); 65 SetGlobalPoolAllocator(&allocator); 66} 67 68TShHandleBase::~TShHandleBase() { 69 SetGlobalPoolAllocator(NULL); 70 allocator.popAll(); 71} 72 73TCompiler::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 86TCompiler::~TCompiler() 87{ 88 ASSERT(longNameMap); 89 longNameMap->Release(); 90} 91 92bool 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 116bool 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 228bool 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 278void 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 294bool 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 319void TCompiler::rewriteCSSShader(TIntermNode* root) 320{ 321 RenameFunction renamer("main(", "css_main("); 322 root->traverse(&renamer); 323} 324 325bool TCompiler::validateLimitations(TIntermNode* root) { 326 ValidateLimitations validate(shaderType, infoSink.info); 327 root->traverse(&validate); 328 return validate.numErrors() == 0; 329} 330 331bool 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 357bool 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 379bool TCompiler::enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph) 380{ 381 RestrictFragmentShaderTiming restrictor(infoSink.info); 382 restrictor.enforceRestrictions(graph); 383 return restrictor.numErrors() == 0; 384} 385 386bool TCompiler::enforceVertexShaderTimingRestrictions(TIntermNode* root) 387{ 388 RestrictVertexShaderTiming restrictor(infoSink.info); 389 restrictor.enforceRestrictions(root); 390 return restrictor.numErrors() == 0; 391} 392 393void TCompiler::collectVariables(TIntermNode* root) 394{ 395 CollectVariables collect(attribs, uniforms, varyings, hashFunction); 396 root->traverse(&collect); 397} 398 399bool TCompiler::enforcePackingRestrictions() 400{ 401 VariablePacker packer; 402 return packer.CheckVariablesWithinPackingLimits(maxUniformVectors, uniforms); 403} 404 405void TCompiler::mapLongVariableNames(TIntermNode* root) 406{ 407 ASSERT(longNameMap); 408 MapLongVariableNames map(longNameMap); 409 root->traverse(&map); 410} 411 412int TCompiler::getMappedNameMaxLength() const 413{ 414 return MAX_SHORTENED_IDENTIFIER_SIZE + 1; 415} 416 417const TExtensionBehavior& TCompiler::getExtensionBehavior() const 418{ 419 return extensionBehavior; 420} 421 422const ShBuiltInResources& TCompiler::getResources() const 423{ 424 return compileResources; 425} 426 427const ArrayBoundsClamper& TCompiler::getArrayBoundsClamper() const 428{ 429 return arrayBoundsClamper; 430} 431 432ShArrayIndexClampingStrategy TCompiler::getArrayIndexClampingStrategy() const 433{ 434 return clampingStrategy; 435} 436 437const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const 438{ 439 return builtInFunctionEmulator; 440} 441