gfx/angle/src/compiler/Compiler.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial