1 // 2 // Copyright (c) 2002-2014 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/BuiltInFunctionEmulator.h" 8 #include "compiler/translator/DetectCallDepth.h" 9 #include "compiler/translator/ForLoopUnroll.h" 10 #include "compiler/translator/Initialize.h" 11 #include "compiler/translator/InitializeParseContext.h" 12 #include "compiler/translator/InitializeVariables.h" 13 #include "compiler/translator/ParseContext.h" 14 #include "compiler/translator/RenameFunction.h" 15 #include "compiler/translator/ShHandle.h" 16 #include "compiler/translator/UnfoldShortCircuitAST.h" 17 #include "compiler/translator/ValidateLimitations.h" 18 #include "compiler/translator/ValidateOutputs.h" 19 #include "compiler/translator/VariablePacker.h" 20 #include "compiler/translator/depgraph/DependencyGraph.h" 21 #include "compiler/translator/depgraph/DependencyGraphOutput.h" 22 #include "compiler/translator/timing/RestrictFragmentShaderTiming.h" 23 #include "compiler/translator/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 size_t GetGlobalMaxTokenSize(ShShaderSpec spec) 32 { 33 // WebGL defines a max token legnth of 256, while ES2 leaves max token 34 // size undefined. ES3 defines a max size of 1024 characters. 35 if (IsWebGLBasedSpec(spec)) 36 { 37 return 256; 38 } 39 else 40 { 41 return 1024; 42 } 43 } 44 45 namespace { 46 class TScopedPoolAllocator 47 { 48 public: 49 TScopedPoolAllocator(TPoolAllocator* allocator) : mAllocator(allocator) 50 { 51 mAllocator->push(); 52 SetGlobalPoolAllocator(mAllocator); 53 } 54 ~TScopedPoolAllocator() 55 { 56 SetGlobalPoolAllocator(NULL); 57 mAllocator->pop(); 58 } 59 60 private: 61 TPoolAllocator* mAllocator; 62 }; 63 64 class TScopedSymbolTableLevel 65 { 66 public: 67 TScopedSymbolTableLevel(TSymbolTable* table) : mTable(table) 68 { 69 ASSERT(mTable->atBuiltInLevel()); 70 mTable->push(); 71 } 72 ~TScopedSymbolTableLevel() 73 { 74 while (!mTable->atBuiltInLevel()) 75 mTable->pop(); 76 } 77 78 private: 79 TSymbolTable* mTable; 80 }; 81 } // namespace 82 83 TShHandleBase::TShHandleBase() 84 { 85 allocator.push(); 86 SetGlobalPoolAllocator(&allocator); 87 } 88 89 TShHandleBase::~TShHandleBase() 90 { 91 SetGlobalPoolAllocator(NULL); 92 allocator.popAll(); 93 } 94 95 TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec, ShShaderOutput output) 96 : shaderType(type), 97 shaderSpec(spec), 98 outputType(output), 99 maxUniformVectors(0), 100 maxExpressionComplexity(0), 101 maxCallStackDepth(0), 102 fragmentPrecisionHigh(false), 103 clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC), 104 builtInFunctionEmulator(type) 105 { 106 } 107 108 TCompiler::~TCompiler() 109 { 110 } 111 112 bool TCompiler::Init(const ShBuiltInResources& resources) 113 { 114 shaderVersion = 100; 115 maxUniformVectors = (shaderType == SH_VERTEX_SHADER) ? 116 resources.MaxVertexUniformVectors : 117 resources.MaxFragmentUniformVectors; 118 maxExpressionComplexity = resources.MaxExpressionComplexity; 119 maxCallStackDepth = resources.MaxCallStackDepth; 120 121 SetGlobalPoolAllocator(&allocator); 122 123 // Generate built-in symbol table. 124 if (!InitBuiltInSymbolTable(resources)) 125 return false; 126 InitExtensionBehavior(resources, extensionBehavior); 127 fragmentPrecisionHigh = resources.FragmentPrecisionHigh == 1; 128 129 arrayBoundsClamper.SetClampingStrategy(resources.ArrayIndexClampingStrategy); 130 clampingStrategy = resources.ArrayIndexClampingStrategy; 131 132 hashFunction = resources.HashFunction; 133 134 return true; 135 } 136 137 bool TCompiler::compile(const char* const shaderStrings[], 138 size_t numStrings, 139 int compileOptions) 140 { 141 TScopedPoolAllocator scopedAlloc(&allocator); 142 clearResults(); 143 144 if (numStrings == 0) 145 return true; 146 147 // If compiling for WebGL, validate loop and indexing as well. 148 if (IsWebGLBasedSpec(shaderSpec)) 149 compileOptions |= SH_VALIDATE_LOOP_INDEXING; 150 151 // First string is path of source file if flag is set. The actual source follows. 152 const char* sourcePath = NULL; 153 size_t firstSource = 0; 154 if (compileOptions & SH_SOURCE_PATH) 155 { 156 sourcePath = shaderStrings[0]; 157 ++firstSource; 158 } 159 160 TIntermediate intermediate(infoSink); 161 TParseContext parseContext(symbolTable, extensionBehavior, intermediate, 162 shaderType, shaderSpec, compileOptions, true, 163 sourcePath, infoSink); 164 parseContext.fragmentPrecisionHigh = fragmentPrecisionHigh; 165 SetGlobalParseContext(&parseContext); 166 167 // We preserve symbols at the built-in level from compile-to-compile. 168 // Start pushing the user-defined symbols at global level. 169 TScopedSymbolTableLevel scopedSymbolLevel(&symbolTable); 170 171 // Parse shader. 172 bool success = 173 (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) && 174 (parseContext.treeRoot != NULL); 175 176 shaderVersion = parseContext.getShaderVersion(); 177 178 if (success) 179 { 180 TIntermNode* root = parseContext.treeRoot; 181 success = intermediate.postProcess(root); 182 183 // Disallow expressions deemed too complex. 184 if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY)) 185 success = limitExpressionComplexity(root); 186 187 if (success) 188 success = detectCallDepth(root, infoSink, (compileOptions & SH_LIMIT_CALL_STACK_DEPTH) != 0); 189 190 if (success && shaderVersion == 300 && shaderType == SH_FRAGMENT_SHADER) 191 success = validateOutputs(root); 192 193 if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING)) 194 success = validateLimitations(root); 195 196 if (success && (compileOptions & SH_TIMING_RESTRICTIONS)) 197 success = enforceTimingRestrictions(root, (compileOptions & SH_DEPENDENCY_GRAPH) != 0); 198 199 if (success && shaderSpec == SH_CSS_SHADERS_SPEC) 200 rewriteCSSShader(root); 201 202 // Unroll for-loop markup needs to happen after validateLimitations pass. 203 if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX)) 204 { 205 ForLoopUnrollMarker marker(ForLoopUnrollMarker::kIntegerIndex); 206 root->traverse(&marker); 207 } 208 if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX)) 209 { 210 ForLoopUnrollMarker marker(ForLoopUnrollMarker::kSamplerArrayIndex); 211 root->traverse(&marker); 212 if (marker.samplerArrayIndexIsFloatLoopIndex()) 213 { 214 infoSink.info.prefix(EPrefixError); 215 infoSink.info << "sampler array index is float loop index"; 216 success = false; 217 } 218 } 219 220 // Built-in function emulation needs to happen after validateLimitations pass. 221 if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS)) 222 builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root); 223 224 // Clamping uniform array bounds needs to happen after validateLimitations pass. 225 if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS)) 226 arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root); 227 228 if (success && shaderType == SH_VERTEX_SHADER && (compileOptions & SH_INIT_GL_POSITION)) 229 initializeGLPosition(root); 230 231 if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT)) 232 { 233 UnfoldShortCircuitAST unfoldShortCircuit; 234 root->traverse(&unfoldShortCircuit); 235 unfoldShortCircuit.updateTree(); 236 } 237 238 if (success && (compileOptions & SH_VARIABLES)) 239 { 240 collectVariables(root); 241 if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS) 242 { 243 success = enforcePackingRestrictions(); 244 if (!success) 245 { 246 infoSink.info.prefix(EPrefixError); 247 infoSink.info << "too many uniforms"; 248 } 249 } 250 if (success && shaderType == SH_VERTEX_SHADER && 251 (compileOptions & SH_INIT_VARYINGS_WITHOUT_STATIC_USE)) 252 initializeVaryingsWithoutStaticUse(root); 253 } 254 255 if (success && (compileOptions & SH_INTERMEDIATE_TREE)) 256 intermediate.outputTree(root); 257 258 if (success && (compileOptions & SH_OBJECT_CODE)) 259 translate(root); 260 } 261 262 // Cleanup memory. 263 intermediate.remove(parseContext.treeRoot); 264 SetGlobalParseContext(NULL); 265 return success; 266 } 267 268 bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources) 269 { 270 compileResources = resources; 271 setResourceString(); 272 273 assert(symbolTable.isEmpty()); 274 symbolTable.push(); // COMMON_BUILTINS 275 symbolTable.push(); // ESSL1_BUILTINS 276 symbolTable.push(); // ESSL3_BUILTINS 277 278 TPublicType integer; 279 integer.type = EbtInt; 280 integer.primarySize = 1; 281 integer.secondarySize = 1; 282 integer.array = false; 283 284 TPublicType floatingPoint; 285 floatingPoint.type = EbtFloat; 286 floatingPoint.primarySize = 1; 287 floatingPoint.secondarySize = 1; 288 floatingPoint.array = false; 289 290 TPublicType sampler; 291 sampler.primarySize = 1; 292 sampler.secondarySize = 1; 293 sampler.array = false; 294 295 switch(shaderType) 296 { 297 case SH_FRAGMENT_SHADER: 298 symbolTable.setDefaultPrecision(integer, EbpMedium); 299 break; 300 case SH_VERTEX_SHADER: 301 symbolTable.setDefaultPrecision(integer, EbpHigh); 302 symbolTable.setDefaultPrecision(floatingPoint, EbpHigh); 303 break; 304 default: 305 assert(false && "Language not supported"); 306 } 307 // We set defaults for all the sampler types, even those that are 308 // only available if an extension exists. 309 for (int samplerType = EbtGuardSamplerBegin + 1; 310 samplerType < EbtGuardSamplerEnd; ++samplerType) 311 { 312 sampler.type = static_cast<TBasicType>(samplerType); 313 symbolTable.setDefaultPrecision(sampler, EbpLow); 314 } 315 316 InsertBuiltInFunctions(shaderType, shaderSpec, resources, symbolTable); 317 318 IdentifyBuiltIns(shaderType, shaderSpec, resources, symbolTable); 319 320 return true; 321 } 322 323 void TCompiler::setResourceString() 324 { 325 std::ostringstream strstream; 326 strstream << ":MaxVertexAttribs:" << compileResources.MaxVertexAttribs 327 << ":MaxVertexUniformVectors:" << compileResources.MaxVertexUniformVectors 328 << ":MaxVaryingVectors:" << compileResources.MaxVaryingVectors 329 << ":MaxVertexTextureImageUnits:" << compileResources.MaxVertexTextureImageUnits 330 << ":MaxCombinedTextureImageUnits:" << compileResources.MaxCombinedTextureImageUnits 331 << ":MaxTextureImageUnits:" << compileResources.MaxTextureImageUnits 332 << ":MaxFragmentUniformVectors:" << compileResources.MaxFragmentUniformVectors 333 << ":MaxDrawBuffers:" << compileResources.MaxDrawBuffers 334 << ":OES_standard_derivatives:" << compileResources.OES_standard_derivatives 335 << ":OES_EGL_image_external:" << compileResources.OES_EGL_image_external 336 << ":ARB_texture_rectangle:" << compileResources.ARB_texture_rectangle 337 << ":EXT_draw_buffers:" << compileResources.EXT_draw_buffers 338 << ":FragmentPrecisionHigh:" << compileResources.FragmentPrecisionHigh 339 << ":MaxExpressionComplexity:" << compileResources.MaxExpressionComplexity 340 << ":MaxCallStackDepth:" << compileResources.MaxCallStackDepth 341 << ":EXT_frag_depth:" << compileResources.EXT_frag_depth 342 << ":EXT_shader_texture_lod:" << compileResources.EXT_shader_texture_lod 343 << ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors 344 << ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors 345 << ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset 346 << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset; 347 348 builtInResourcesString = strstream.str(); 349 } 350 351 void TCompiler::clearResults() 352 { 353 arrayBoundsClamper.Cleanup(); 354 infoSink.info.erase(); 355 infoSink.obj.erase(); 356 infoSink.debug.erase(); 357 358 attribs.clear(); 359 uniforms.clear(); 360 varyings.clear(); 361 362 builtInFunctionEmulator.Cleanup(); 363 364 nameMap.clear(); 365 } 366 367 bool TCompiler::detectCallDepth(TIntermNode* root, TInfoSink& infoSink, bool limitCallStackDepth) 368 { 369 DetectCallDepth detect(infoSink, limitCallStackDepth, maxCallStackDepth); 370 root->traverse(&detect); 371 switch (detect.detectCallDepth()) 372 { 373 case DetectCallDepth::kErrorNone: 374 return true; 375 case DetectCallDepth::kErrorMissingMain: 376 infoSink.info.prefix(EPrefixError); 377 infoSink.info << "Missing main()"; 378 return false; 379 case DetectCallDepth::kErrorRecursion: 380 infoSink.info.prefix(EPrefixError); 381 infoSink.info << "Function recursion detected"; 382 return false; 383 case DetectCallDepth::kErrorMaxDepthExceeded: 384 infoSink.info.prefix(EPrefixError); 385 infoSink.info << "Function call stack too deep"; 386 return false; 387 default: 388 UNREACHABLE(); 389 return false; 390 } 391 } 392 393 bool TCompiler::validateOutputs(TIntermNode* root) 394 { 395 ValidateOutputs validateOutputs(infoSink.info, compileResources.MaxDrawBuffers); 396 root->traverse(&validateOutputs); 397 return (validateOutputs.numErrors() == 0); 398 } 399 400 void TCompiler::rewriteCSSShader(TIntermNode* root) 401 { 402 RenameFunction renamer("main(", "css_main("); 403 root->traverse(&renamer); 404 } 405 406 bool TCompiler::validateLimitations(TIntermNode* root) 407 { 408 ValidateLimitations validate(shaderType, infoSink.info); 409 root->traverse(&validate); 410 return validate.numErrors() == 0; 411 } 412 413 bool TCompiler::enforceTimingRestrictions(TIntermNode* root, bool outputGraph) 414 { 415 if (shaderSpec != SH_WEBGL_SPEC) 416 { 417 infoSink.info << "Timing restrictions must be enforced under the WebGL spec."; 418 return false; 419 } 420 421 if (shaderType == SH_FRAGMENT_SHADER) 422 { 423 TDependencyGraph graph(root); 424 425 // Output any errors first. 426 bool success = enforceFragmentShaderTimingRestrictions(graph); 427 428 // Then, output the dependency graph. 429 if (outputGraph) 430 { 431 TDependencyGraphOutput output(infoSink.info); 432 output.outputAllSpanningTrees(graph); 433 } 434 435 return success; 436 } 437 else 438 { 439 return enforceVertexShaderTimingRestrictions(root); 440 } 441 } 442 443 bool TCompiler::limitExpressionComplexity(TIntermNode* root) 444 { 445 TMaxDepthTraverser traverser(maxExpressionComplexity+1); 446 root->traverse(&traverser); 447 448 if (traverser.getMaxDepth() > maxExpressionComplexity) 449 { 450 infoSink.info << "Expression too complex."; 451 return false; 452 } 453 454 TDependencyGraph graph(root); 455 456 for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls(); 457 iter != graph.endUserDefinedFunctionCalls(); 458 ++iter) 459 { 460 TGraphFunctionCall* samplerSymbol = *iter; 461 TDependencyGraphTraverser graphTraverser; 462 samplerSymbol->traverse(&graphTraverser); 463 } 464 465 return true; 466 } 467 468 bool TCompiler::enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph) 469 { 470 RestrictFragmentShaderTiming restrictor(infoSink.info); 471 restrictor.enforceRestrictions(graph); 472 return restrictor.numErrors() == 0; 473 } 474 475 bool TCompiler::enforceVertexShaderTimingRestrictions(TIntermNode* root) 476 { 477 RestrictVertexShaderTiming restrictor(infoSink.info); 478 restrictor.enforceRestrictions(root); 479 return restrictor.numErrors() == 0; 480 } 481 482 void TCompiler::collectVariables(TIntermNode* root) 483 { 484 CollectVariables collect(attribs, uniforms, varyings, hashFunction); 485 root->traverse(&collect); 486 } 487 488 bool TCompiler::enforcePackingRestrictions() 489 { 490 VariablePacker packer; 491 return packer.CheckVariablesWithinPackingLimits(maxUniformVectors, uniforms); 492 } 493 494 void TCompiler::initializeGLPosition(TIntermNode* root) 495 { 496 InitializeVariables::InitVariableInfoList variables; 497 InitializeVariables::InitVariableInfo var( 498 "gl_Position", TType(EbtFloat, EbpUndefined, EvqPosition, 4)); 499 variables.push_back(var); 500 InitializeVariables initializer(variables); 501 root->traverse(&initializer); 502 } 503 504 void TCompiler::initializeVaryingsWithoutStaticUse(TIntermNode* root) 505 { 506 InitializeVariables::InitVariableInfoList variables; 507 for (size_t ii = 0; ii < varyings.size(); ++ii) 508 { 509 const TVariableInfo& varying = varyings[ii]; 510 if (varying.staticUse) 511 continue; 512 unsigned char primarySize = 1, secondarySize = 1; 513 switch (varying.type) 514 { 515 case SH_FLOAT: 516 break; 517 case SH_FLOAT_VEC2: 518 primarySize = 2; 519 break; 520 case SH_FLOAT_VEC3: 521 primarySize = 3; 522 break; 523 case SH_FLOAT_VEC4: 524 primarySize = 4; 525 break; 526 case SH_FLOAT_MAT2: 527 primarySize = 2; 528 secondarySize = 2; 529 break; 530 case SH_FLOAT_MAT3: 531 primarySize = 3; 532 secondarySize = 3; 533 break; 534 case SH_FLOAT_MAT4: 535 primarySize = 4; 536 secondarySize = 4; 537 break; 538 default: 539 ASSERT(false); 540 } 541 TType type(EbtFloat, EbpUndefined, EvqVaryingOut, primarySize, secondarySize, varying.isArray); 542 TString name = varying.name.c_str(); 543 if (varying.isArray) 544 { 545 type.setArraySize(varying.size); 546 name = name.substr(0, name.find_first_of('[')); 547 } 548 549 InitializeVariables::InitVariableInfo var(name, type); 550 variables.push_back(var); 551 } 552 InitializeVariables initializer(variables); 553 root->traverse(&initializer); 554 } 555 556 const TExtensionBehavior& TCompiler::getExtensionBehavior() const 557 { 558 return extensionBehavior; 559 } 560 561 const ShBuiltInResources& TCompiler::getResources() const 562 { 563 return compileResources; 564 } 565 566 const ArrayBoundsClamper& TCompiler::getArrayBoundsClamper() const 567 { 568 return arrayBoundsClamper; 569 } 570 571 ShArrayIndexClampingStrategy TCompiler::getArrayIndexClampingStrategy() const 572 { 573 return clampingStrategy; 574 } 575 576 const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const 577 { 578 return builtInFunctionEmulator; 579 } 580