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 26bool IsWebGLBasedSpec(ShShaderSpec spec) 27{ 28 return spec == SH_WEBGL_SPEC || spec == SH_CSS_SHADERS_SPEC; 29} 30 31size_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 45namespace { 46class 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 64class 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 83TShHandleBase::TShHandleBase() 84{ 85 allocator.push(); 86 SetGlobalPoolAllocator(&allocator); 87} 88 89TShHandleBase::~TShHandleBase() 90{ 91 SetGlobalPoolAllocator(NULL); 92 allocator.popAll(); 93} 94 95TCompiler::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 108TCompiler::~TCompiler() 109{ 110} 111 112bool 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 137bool 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 268bool 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 323void 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 351void 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 367bool 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 393bool TCompiler::validateOutputs(TIntermNode* root) 394{ 395 ValidateOutputs validateOutputs(infoSink.info, compileResources.MaxDrawBuffers); 396 root->traverse(&validateOutputs); 397 return (validateOutputs.numErrors() == 0); 398} 399 400void TCompiler::rewriteCSSShader(TIntermNode* root) 401{ 402 RenameFunction renamer("main(", "css_main("); 403 root->traverse(&renamer); 404} 405 406bool TCompiler::validateLimitations(TIntermNode* root) 407{ 408 ValidateLimitations validate(shaderType, infoSink.info); 409 root->traverse(&validate); 410 return validate.numErrors() == 0; 411} 412 413bool 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 443bool 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 468bool TCompiler::enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph) 469{ 470 RestrictFragmentShaderTiming restrictor(infoSink.info); 471 restrictor.enforceRestrictions(graph); 472 return restrictor.numErrors() == 0; 473} 474 475bool TCompiler::enforceVertexShaderTimingRestrictions(TIntermNode* root) 476{ 477 RestrictVertexShaderTiming restrictor(infoSink.info); 478 restrictor.enforceRestrictions(root); 479 return restrictor.numErrors() == 0; 480} 481 482void TCompiler::collectVariables(TIntermNode* root) 483{ 484 CollectVariables collect(attribs, uniforms, varyings, hashFunction); 485 root->traverse(&collect); 486} 487 488bool TCompiler::enforcePackingRestrictions() 489{ 490 VariablePacker packer; 491 return packer.CheckVariablesWithinPackingLimits(maxUniformVectors, uniforms); 492} 493 494void 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 504void 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 556const TExtensionBehavior& TCompiler::getExtensionBehavior() const 557{ 558 return extensionBehavior; 559} 560 561const ShBuiltInResources& TCompiler::getResources() const 562{ 563 return compileResources; 564} 565 566const ArrayBoundsClamper& TCompiler::getArrayBoundsClamper() const 567{ 568 return arrayBoundsClamper; 569} 570 571ShArrayIndexClampingStrategy TCompiler::getArrayIndexClampingStrategy() const 572{ 573 return clampingStrategy; 574} 575 576const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const 577{ 578 return builtInFunctionEmulator; 579} 580