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