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