Line data Source code
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/Compiler.h"
8 :
9 : #include <sstream>
10 :
11 : #include "angle_gl.h"
12 : #include "common/utilities.h"
13 : #include "compiler/translator/AddAndTrueToLoopCondition.h"
14 : #include "compiler/translator/Cache.h"
15 : #include "compiler/translator/CallDAG.h"
16 : #include "compiler/translator/DeferGlobalInitializers.h"
17 : #include "compiler/translator/EmulateGLFragColorBroadcast.h"
18 : #include "compiler/translator/EmulatePrecision.h"
19 : #include "compiler/translator/Initialize.h"
20 : #include "compiler/translator/InitializeParseContext.h"
21 : #include "compiler/translator/InitializeVariables.h"
22 : #include "compiler/translator/ParseContext.h"
23 : #include "compiler/translator/PruneEmptyDeclarations.h"
24 : #include "compiler/translator/RegenerateStructNames.h"
25 : #include "compiler/translator/RemoveInvariantDeclaration.h"
26 : #include "compiler/translator/RemovePow.h"
27 : #include "compiler/translator/RewriteDoWhile.h"
28 : #include "compiler/translator/ScalarizeVecAndMatConstructorArgs.h"
29 : #include "compiler/translator/UnfoldShortCircuitAST.h"
30 : #include "compiler/translator/UseInterfaceBlockFields.h"
31 : #include "compiler/translator/ValidateLimitations.h"
32 : #include "compiler/translator/ValidateMaxParameters.h"
33 : #include "compiler/translator/ValidateOutputs.h"
34 : #include "compiler/translator/VariablePacker.h"
35 : #include "third_party/compiler/ArrayBoundsClamper.h"
36 :
37 : namespace sh
38 : {
39 :
40 : namespace
41 : {
42 :
43 : #if defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT)
44 : void DumpFuzzerCase(char const *const *shaderStrings,
45 : size_t numStrings,
46 : uint32_t type,
47 : uint32_t spec,
48 : uint32_t output,
49 : uint64_t options)
50 : {
51 : static int fileIndex = 0;
52 :
53 : std::ostringstream o;
54 : o << "corpus/" << fileIndex++ << ".sample";
55 : std::string s = o.str();
56 :
57 : // Must match the input format of the fuzzer
58 : FILE *f = fopen(s.c_str(), "w");
59 : fwrite(&type, sizeof(type), 1, f);
60 : fwrite(&spec, sizeof(spec), 1, f);
61 : fwrite(&output, sizeof(output), 1, f);
62 : fwrite(&options, sizeof(options), 1, f);
63 :
64 : char zero[128 - 20] = {0};
65 : fwrite(&zero, 128 - 20, 1, f);
66 :
67 : for (size_t i = 0; i < numStrings; i++)
68 : {
69 : fwrite(shaderStrings[i], sizeof(char), strlen(shaderStrings[i]), f);
70 : }
71 : fwrite(&zero, 1, 1, f);
72 :
73 : fclose(f);
74 : }
75 : #endif // defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT)
76 : } // anonymous namespace
77 :
78 0 : bool IsWebGLBasedSpec(ShShaderSpec spec)
79 : {
80 0 : return (spec == SH_WEBGL_SPEC || spec == SH_WEBGL2_SPEC || spec == SH_WEBGL3_SPEC);
81 : }
82 :
83 0 : bool IsGLSL130OrNewer(ShShaderOutput output)
84 : {
85 0 : return (output == SH_GLSL_130_OUTPUT || output == SH_GLSL_140_OUTPUT ||
86 0 : output == SH_GLSL_150_CORE_OUTPUT || output == SH_GLSL_330_CORE_OUTPUT ||
87 0 : output == SH_GLSL_400_CORE_OUTPUT || output == SH_GLSL_410_CORE_OUTPUT ||
88 0 : output == SH_GLSL_420_CORE_OUTPUT || output == SH_GLSL_430_CORE_OUTPUT ||
89 0 : output == SH_GLSL_440_CORE_OUTPUT || output == SH_GLSL_450_CORE_OUTPUT);
90 : }
91 :
92 0 : bool IsGLSL420OrNewer(ShShaderOutput output)
93 : {
94 0 : return (output == SH_GLSL_420_CORE_OUTPUT || output == SH_GLSL_430_CORE_OUTPUT ||
95 0 : output == SH_GLSL_440_CORE_OUTPUT || output == SH_GLSL_450_CORE_OUTPUT);
96 : }
97 :
98 0 : bool IsGLSL410OrOlder(ShShaderOutput output)
99 : {
100 0 : return (output == SH_GLSL_130_OUTPUT || output == SH_GLSL_140_OUTPUT ||
101 0 : output == SH_GLSL_150_CORE_OUTPUT || output == SH_GLSL_330_CORE_OUTPUT ||
102 0 : output == SH_GLSL_400_CORE_OUTPUT || output == SH_GLSL_410_CORE_OUTPUT);
103 : }
104 :
105 0 : bool RemoveInvariant(sh::GLenum shaderType,
106 : int shaderVersion,
107 : ShShaderOutput outputType,
108 : ShCompileOptions compileOptions)
109 : {
110 0 : if ((compileOptions & SH_DONT_REMOVE_INVARIANT_FOR_FRAGMENT_INPUT) == 0 &&
111 0 : shaderType == GL_FRAGMENT_SHADER && IsGLSL420OrNewer(outputType))
112 0 : return true;
113 :
114 0 : if ((compileOptions & SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3) != 0 &&
115 0 : shaderVersion >= 300 && shaderType == GL_VERTEX_SHADER)
116 0 : return true;
117 :
118 0 : return false;
119 : }
120 :
121 0 : size_t GetGlobalMaxTokenSize(ShShaderSpec spec)
122 : {
123 : // WebGL defines a max token length of 256, while ES2 leaves max token
124 : // size undefined. ES3 defines a max size of 1024 characters.
125 0 : switch (spec)
126 : {
127 : case SH_WEBGL_SPEC:
128 0 : return 256;
129 : default:
130 0 : return 1024;
131 : }
132 : }
133 :
134 : namespace {
135 :
136 : class TScopedPoolAllocator
137 : {
138 : public:
139 0 : TScopedPoolAllocator(TPoolAllocator* allocator) : mAllocator(allocator)
140 : {
141 0 : mAllocator->push();
142 0 : SetGlobalPoolAllocator(mAllocator);
143 0 : }
144 0 : ~TScopedPoolAllocator()
145 0 : {
146 0 : SetGlobalPoolAllocator(NULL);
147 0 : mAllocator->pop();
148 0 : }
149 :
150 : private:
151 : TPoolAllocator* mAllocator;
152 : };
153 :
154 : class TScopedSymbolTableLevel
155 : {
156 : public:
157 0 : TScopedSymbolTableLevel(TSymbolTable* table) : mTable(table)
158 : {
159 0 : ASSERT(mTable->atBuiltInLevel());
160 0 : mTable->push();
161 0 : }
162 0 : ~TScopedSymbolTableLevel()
163 0 : {
164 0 : while (!mTable->atBuiltInLevel())
165 0 : mTable->pop();
166 0 : }
167 :
168 : private:
169 : TSymbolTable* mTable;
170 : };
171 :
172 0 : int MapSpecToShaderVersion(ShShaderSpec spec)
173 : {
174 0 : switch (spec)
175 : {
176 : case SH_GLES2_SPEC:
177 : case SH_WEBGL_SPEC:
178 0 : return 100;
179 : case SH_GLES3_SPEC:
180 : case SH_WEBGL2_SPEC:
181 0 : return 300;
182 : case SH_GLES3_1_SPEC:
183 : case SH_WEBGL3_SPEC:
184 0 : return 310;
185 : default:
186 0 : UNREACHABLE();
187 : return 0;
188 : }
189 : }
190 :
191 : } // namespace
192 :
193 0 : TShHandleBase::TShHandleBase()
194 : {
195 0 : allocator.push();
196 0 : SetGlobalPoolAllocator(&allocator);
197 0 : }
198 :
199 0 : TShHandleBase::~TShHandleBase()
200 : {
201 0 : SetGlobalPoolAllocator(NULL);
202 0 : allocator.popAll();
203 0 : }
204 :
205 0 : TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
206 : : variablesCollected(false),
207 : shaderType(type),
208 : shaderSpec(spec),
209 : outputType(output),
210 : maxUniformVectors(0),
211 : maxExpressionComplexity(0),
212 : maxCallStackDepth(0),
213 : maxFunctionParameters(0),
214 : fragmentPrecisionHigh(false),
215 : clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC),
216 : builtInFunctionEmulator(),
217 : mSourcePath(NULL),
218 : mComputeShaderLocalSizeDeclared(false),
219 0 : mTemporaryIndex(0)
220 : {
221 0 : mComputeShaderLocalSize.fill(1);
222 0 : }
223 :
224 0 : TCompiler::~TCompiler()
225 : {
226 0 : }
227 :
228 0 : bool TCompiler::shouldRunLoopAndIndexingValidation(ShCompileOptions compileOptions) const
229 : {
230 : // If compiling an ESSL 1.00 shader for WebGL, or if its been requested through the API,
231 : // validate loop and indexing as well (to verify that the shader only uses minimal functionality
232 : // of ESSL 1.00 as in Appendix A of the spec).
233 0 : return (IsWebGLBasedSpec(shaderSpec) && shaderVersion == 100) ||
234 0 : (compileOptions & SH_VALIDATE_LOOP_INDEXING);
235 : }
236 :
237 0 : bool TCompiler::Init(const ShBuiltInResources& resources)
238 : {
239 0 : shaderVersion = 100;
240 0 : maxUniformVectors = (shaderType == GL_VERTEX_SHADER) ?
241 : resources.MaxVertexUniformVectors :
242 : resources.MaxFragmentUniformVectors;
243 0 : maxExpressionComplexity = resources.MaxExpressionComplexity;
244 0 : maxCallStackDepth = resources.MaxCallStackDepth;
245 0 : maxFunctionParameters = resources.MaxFunctionParameters;
246 :
247 0 : SetGlobalPoolAllocator(&allocator);
248 :
249 : // Generate built-in symbol table.
250 0 : if (!InitBuiltInSymbolTable(resources))
251 0 : return false;
252 0 : InitExtensionBehavior(resources, extensionBehavior);
253 0 : fragmentPrecisionHigh = resources.FragmentPrecisionHigh == 1;
254 :
255 0 : arrayBoundsClamper.SetClampingStrategy(resources.ArrayIndexClampingStrategy);
256 0 : clampingStrategy = resources.ArrayIndexClampingStrategy;
257 :
258 0 : hashFunction = resources.HashFunction;
259 :
260 0 : return true;
261 : }
262 :
263 0 : TIntermBlock *TCompiler::compileTreeForTesting(const char *const shaderStrings[],
264 : size_t numStrings,
265 : ShCompileOptions compileOptions)
266 : {
267 0 : return compileTreeImpl(shaderStrings, numStrings, compileOptions);
268 : }
269 :
270 0 : TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
271 : size_t numStrings,
272 : const ShCompileOptions compileOptions)
273 : {
274 0 : clearResults();
275 :
276 0 : ASSERT(numStrings > 0);
277 0 : ASSERT(GetGlobalPoolAllocator());
278 :
279 : // Reset the extension behavior for each compilation unit.
280 0 : ResetExtensionBehavior(extensionBehavior);
281 :
282 : // First string is path of source file if flag is set. The actual source follows.
283 0 : size_t firstSource = 0;
284 0 : if (compileOptions & SH_SOURCE_PATH)
285 : {
286 0 : mSourcePath = shaderStrings[0];
287 0 : ++firstSource;
288 : }
289 :
290 : TParseContext parseContext(symbolTable, extensionBehavior, shaderType, shaderSpec,
291 0 : compileOptions, true, infoSink, getResources());
292 :
293 0 : parseContext.setFragmentPrecisionHighOnESSL1(fragmentPrecisionHigh);
294 0 : SetGlobalParseContext(&parseContext);
295 :
296 : // We preserve symbols at the built-in level from compile-to-compile.
297 : // Start pushing the user-defined symbols at global level.
298 0 : TScopedSymbolTableLevel scopedSymbolLevel(&symbolTable);
299 :
300 : // Parse shader.
301 : bool success =
302 0 : (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], nullptr, &parseContext) == 0) &&
303 0 : (parseContext.getTreeRoot() != nullptr);
304 :
305 0 : shaderVersion = parseContext.getShaderVersion();
306 0 : if (success && MapSpecToShaderVersion(shaderSpec) < shaderVersion)
307 : {
308 0 : infoSink.info.prefix(EPrefixError);
309 0 : infoSink.info << "unsupported shader version";
310 0 : success = false;
311 : }
312 :
313 0 : TIntermBlock *root = nullptr;
314 :
315 0 : if (success)
316 : {
317 0 : mPragma = parseContext.pragma();
318 0 : symbolTable.setGlobalInvariant(mPragma.stdgl.invariantAll);
319 :
320 0 : mComputeShaderLocalSizeDeclared = parseContext.isComputeShaderLocalSizeDeclared();
321 0 : mComputeShaderLocalSize = parseContext.getComputeShaderLocalSize();
322 :
323 0 : root = parseContext.getTreeRoot();
324 :
325 : // Highp might have been auto-enabled based on shader version
326 0 : fragmentPrecisionHigh = parseContext.getFragmentPrecisionHigh();
327 :
328 : // Disallow expressions deemed too complex.
329 0 : if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY))
330 0 : success = limitExpressionComplexity(root);
331 :
332 : // Create the function DAG and check there is no recursion
333 0 : if (success)
334 0 : success = initCallDag(root);
335 :
336 0 : if (success && (compileOptions & SH_LIMIT_CALL_STACK_DEPTH))
337 0 : success = checkCallDepth();
338 :
339 : // Checks which functions are used and if "main" exists
340 0 : if (success)
341 : {
342 0 : functionMetadata.clear();
343 0 : functionMetadata.resize(mCallDag.size());
344 0 : success = tagUsedFunctions();
345 : }
346 :
347 0 : if (success && !(compileOptions & SH_DONT_PRUNE_UNUSED_FUNCTIONS))
348 0 : success = pruneUnusedFunctions(root);
349 :
350 : // Prune empty declarations to work around driver bugs and to keep declaration output simple.
351 0 : if (success)
352 0 : PruneEmptyDeclarations(root);
353 :
354 0 : if (success && shaderVersion == 300 && shaderType == GL_FRAGMENT_SHADER)
355 0 : success = validateOutputs(root);
356 :
357 0 : if (success && shouldRunLoopAndIndexingValidation(compileOptions))
358 0 : success = validateLimitations(root);
359 :
360 : // Fail compilation if precision emulation not supported.
361 0 : if (success && getResources().WEBGL_debug_shader_precision &&
362 0 : getPragma().debugShaderPrecision)
363 : {
364 0 : if (!EmulatePrecision::SupportedInLanguage(outputType))
365 : {
366 0 : infoSink.info.prefix(EPrefixError);
367 0 : infoSink.info << "Precision emulation not supported for this output type.";
368 0 : success = false;
369 : }
370 : }
371 :
372 : // Built-in function emulation needs to happen after validateLimitations pass.
373 0 : if (success)
374 : {
375 : // TODO(jmadill): Remove global pool allocator.
376 0 : GetGlobalPoolAllocator()->lock();
377 0 : initBuiltInFunctionEmulator(&builtInFunctionEmulator, compileOptions);
378 0 : GetGlobalPoolAllocator()->unlock();
379 0 : builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root);
380 : }
381 :
382 : // Clamping uniform array bounds needs to happen after validateLimitations pass.
383 0 : if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS))
384 0 : arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root);
385 :
386 : // gl_Position is always written in compatibility output mode
387 0 : if (success && shaderType == GL_VERTEX_SHADER &&
388 0 : ((compileOptions & SH_INIT_GL_POSITION) ||
389 0 : (outputType == SH_GLSL_COMPATIBILITY_OUTPUT)))
390 0 : initializeGLPosition(root);
391 :
392 0 : if (success && RemoveInvariant(shaderType, shaderVersion, outputType, compileOptions))
393 0 : sh::RemoveInvariantDeclaration(root);
394 :
395 : // This pass might emit short circuits so keep it before the short circuit unfolding
396 0 : if (success && (compileOptions & SH_REWRITE_DO_WHILE_LOOPS))
397 0 : RewriteDoWhile(root, getTemporaryIndex());
398 :
399 0 : if (success && (compileOptions & SH_ADD_AND_TRUE_TO_LOOP_CONDITION))
400 0 : sh::AddAndTrueToLoopCondition(root);
401 :
402 0 : if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT))
403 : {
404 0 : UnfoldShortCircuitAST unfoldShortCircuit;
405 0 : root->traverse(&unfoldShortCircuit);
406 0 : unfoldShortCircuit.updateTree();
407 : }
408 :
409 0 : if (success && (compileOptions & SH_REMOVE_POW_WITH_CONSTANT_EXPONENT))
410 : {
411 0 : RemovePow(root);
412 : }
413 :
414 0 : if (success && shouldCollectVariables(compileOptions))
415 : {
416 0 : collectVariables(root);
417 0 : if (compileOptions & SH_USE_UNUSED_STANDARD_SHARED_BLOCKS)
418 : {
419 0 : useAllMembersInUnusedStandardAndSharedBlocks(root);
420 : }
421 0 : if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS)
422 : {
423 0 : success = enforcePackingRestrictions();
424 0 : if (!success)
425 : {
426 0 : infoSink.info.prefix(EPrefixError);
427 0 : infoSink.info << "too many uniforms";
428 : }
429 : }
430 0 : if (success && (compileOptions & SH_INIT_OUTPUT_VARIABLES))
431 : {
432 0 : initializeOutputVariables(root);
433 : }
434 : }
435 :
436 0 : if (success && (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS))
437 : {
438 0 : ScalarizeVecAndMatConstructorArgs(root, shaderType, fragmentPrecisionHigh,
439 0 : &mTemporaryIndex);
440 : }
441 :
442 0 : if (success && (compileOptions & SH_REGENERATE_STRUCT_NAMES))
443 : {
444 0 : RegenerateStructNames gen(symbolTable, shaderVersion);
445 0 : root->traverse(&gen);
446 : }
447 :
448 0 : if (success && shaderType == GL_FRAGMENT_SHADER && shaderVersion == 100 &&
449 0 : compileResources.EXT_draw_buffers && compileResources.MaxDrawBuffers > 1 &&
450 0 : IsExtensionEnabled(extensionBehavior, "GL_EXT_draw_buffers"))
451 : {
452 0 : EmulateGLFragColorBroadcast(root, compileResources.MaxDrawBuffers, &outputVariables);
453 : }
454 :
455 0 : if (success)
456 : {
457 0 : DeferGlobalInitializers(root);
458 : }
459 : }
460 :
461 0 : SetGlobalParseContext(NULL);
462 0 : if (success)
463 0 : return root;
464 :
465 0 : return NULL;
466 : }
467 :
468 0 : bool TCompiler::compile(const char *const shaderStrings[],
469 : size_t numStrings,
470 : ShCompileOptions compileOptionsIn)
471 : {
472 : #if defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT)
473 : DumpFuzzerCase(shaderStrings, numStrings, shaderType, shaderSpec, outputType, compileOptionsIn);
474 : #endif // defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT)
475 :
476 0 : if (numStrings == 0)
477 0 : return true;
478 :
479 0 : ShCompileOptions compileOptions = compileOptionsIn;
480 :
481 : // Apply key workarounds.
482 0 : if (shouldFlattenPragmaStdglInvariantAll())
483 : {
484 : // This should be harmless to do in all cases, but for the moment, do it only conditionally.
485 0 : compileOptions |= SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL;
486 : }
487 :
488 0 : TScopedPoolAllocator scopedAlloc(&allocator);
489 0 : TIntermBlock *root = compileTreeImpl(shaderStrings, numStrings, compileOptions);
490 :
491 0 : if (root)
492 : {
493 0 : if (compileOptions & SH_INTERMEDIATE_TREE)
494 0 : TIntermediate::outputTree(root, infoSink.info);
495 :
496 0 : if (compileOptions & SH_OBJECT_CODE)
497 0 : translate(root, compileOptions);
498 :
499 : // The IntermNode tree doesn't need to be deleted here, since the
500 : // memory will be freed in a big chunk by the PoolAllocator.
501 0 : return true;
502 : }
503 0 : return false;
504 : }
505 :
506 0 : bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
507 : {
508 0 : if (resources.MaxDrawBuffers < 1)
509 : {
510 0 : return false;
511 : }
512 0 : if (resources.EXT_blend_func_extended && resources.MaxDualSourceDrawBuffers < 1)
513 : {
514 0 : return false;
515 : }
516 :
517 0 : compileResources = resources;
518 0 : setResourceString();
519 :
520 0 : assert(symbolTable.isEmpty());
521 0 : symbolTable.push(); // COMMON_BUILTINS
522 0 : symbolTable.push(); // ESSL1_BUILTINS
523 0 : symbolTable.push(); // ESSL3_BUILTINS
524 0 : symbolTable.push(); // ESSL3_1_BUILTINS
525 :
526 : TPublicType integer;
527 0 : integer.initializeBasicType(EbtInt);
528 :
529 : TPublicType floatingPoint;
530 0 : floatingPoint.initializeBasicType(EbtFloat);
531 :
532 0 : switch (shaderType)
533 : {
534 : case GL_FRAGMENT_SHADER:
535 0 : symbolTable.setDefaultPrecision(integer, EbpMedium);
536 0 : break;
537 : case GL_VERTEX_SHADER:
538 0 : symbolTable.setDefaultPrecision(integer, EbpHigh);
539 0 : symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
540 0 : break;
541 : case GL_COMPUTE_SHADER:
542 0 : symbolTable.setDefaultPrecision(integer, EbpHigh);
543 0 : symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
544 0 : break;
545 : default:
546 0 : assert(false && "Language not supported");
547 : }
548 : // Set defaults for sampler types that have default precision, even those that are
549 : // only available if an extension exists.
550 : // New sampler types in ESSL3 don't have default precision. ESSL1 types do.
551 0 : initSamplerDefaultPrecision(EbtSampler2D);
552 0 : initSamplerDefaultPrecision(EbtSamplerCube);
553 : // SamplerExternalOES is specified in the extension to have default precision.
554 0 : initSamplerDefaultPrecision(EbtSamplerExternalOES);
555 : // It isn't specified whether Sampler2DRect has default precision.
556 0 : initSamplerDefaultPrecision(EbtSampler2DRect);
557 :
558 0 : InsertBuiltInFunctions(shaderType, shaderSpec, resources, symbolTable);
559 :
560 0 : IdentifyBuiltIns(shaderType, shaderSpec, resources, symbolTable);
561 :
562 0 : return true;
563 : }
564 :
565 0 : void TCompiler::initSamplerDefaultPrecision(TBasicType samplerType)
566 : {
567 0 : ASSERT(samplerType > EbtGuardSamplerBegin && samplerType < EbtGuardSamplerEnd);
568 : TPublicType sampler;
569 0 : sampler.initializeBasicType(samplerType);
570 0 : symbolTable.setDefaultPrecision(sampler, EbpLow);
571 0 : }
572 :
573 0 : void TCompiler::setResourceString()
574 : {
575 0 : std::ostringstream strstream;
576 :
577 : // clang-format off
578 0 : strstream << ":MaxVertexAttribs:" << compileResources.MaxVertexAttribs
579 0 : << ":MaxVertexUniformVectors:" << compileResources.MaxVertexUniformVectors
580 0 : << ":MaxVaryingVectors:" << compileResources.MaxVaryingVectors
581 0 : << ":MaxVertexTextureImageUnits:" << compileResources.MaxVertexTextureImageUnits
582 0 : << ":MaxCombinedTextureImageUnits:" << compileResources.MaxCombinedTextureImageUnits
583 0 : << ":MaxTextureImageUnits:" << compileResources.MaxTextureImageUnits
584 0 : << ":MaxFragmentUniformVectors:" << compileResources.MaxFragmentUniformVectors
585 0 : << ":MaxDrawBuffers:" << compileResources.MaxDrawBuffers
586 0 : << ":OES_standard_derivatives:" << compileResources.OES_standard_derivatives
587 0 : << ":OES_EGL_image_external:" << compileResources.OES_EGL_image_external
588 0 : << ":OES_EGL_image_external_essl3:" << compileResources.OES_EGL_image_external_essl3
589 0 : << ":NV_EGL_stream_consumer_external:" << compileResources.NV_EGL_stream_consumer_external
590 0 : << ":ARB_texture_rectangle:" << compileResources.ARB_texture_rectangle
591 0 : << ":EXT_draw_buffers:" << compileResources.EXT_draw_buffers
592 0 : << ":FragmentPrecisionHigh:" << compileResources.FragmentPrecisionHigh
593 0 : << ":MaxExpressionComplexity:" << compileResources.MaxExpressionComplexity
594 0 : << ":MaxCallStackDepth:" << compileResources.MaxCallStackDepth
595 0 : << ":MaxFunctionParameters:" << compileResources.MaxFunctionParameters
596 0 : << ":EXT_blend_func_extended:" << compileResources.EXT_blend_func_extended
597 0 : << ":EXT_frag_depth:" << compileResources.EXT_frag_depth
598 0 : << ":EXT_shader_texture_lod:" << compileResources.EXT_shader_texture_lod
599 0 : << ":EXT_shader_framebuffer_fetch:" << compileResources.EXT_shader_framebuffer_fetch
600 0 : << ":NV_shader_framebuffer_fetch:" << compileResources.NV_shader_framebuffer_fetch
601 0 : << ":ARM_shader_framebuffer_fetch:" << compileResources.ARM_shader_framebuffer_fetch
602 0 : << ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors
603 0 : << ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors
604 0 : << ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset
605 0 : << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset
606 0 : << ":MaxDualSourceDrawBuffers:" << compileResources.MaxDualSourceDrawBuffers
607 0 : << ":NV_draw_buffers:" << compileResources.NV_draw_buffers
608 0 : << ":WEBGL_debug_shader_precision:" << compileResources.WEBGL_debug_shader_precision
609 0 : << ":MaxImageUnits:" << compileResources.MaxImageUnits
610 0 : << ":MaxVertexImageUniforms:" << compileResources.MaxVertexImageUniforms
611 0 : << ":MaxFragmentImageUniforms:" << compileResources.MaxFragmentImageUniforms
612 0 : << ":MaxComputeImageUniforms:" << compileResources.MaxComputeImageUniforms
613 0 : << ":MaxCombinedImageUniforms:" << compileResources.MaxCombinedImageUniforms
614 0 : << ":MaxCombinedShaderOutputResources:" << compileResources.MaxCombinedShaderOutputResources
615 0 : << ":MaxComputeWorkGroupCountX:" << compileResources.MaxComputeWorkGroupCount[0]
616 0 : << ":MaxComputeWorkGroupCountY:" << compileResources.MaxComputeWorkGroupCount[1]
617 0 : << ":MaxComputeWorkGroupCountZ:" << compileResources.MaxComputeWorkGroupCount[2]
618 0 : << ":MaxComputeWorkGroupSizeX:" << compileResources.MaxComputeWorkGroupSize[0]
619 0 : << ":MaxComputeWorkGroupSizeY:" << compileResources.MaxComputeWorkGroupSize[1]
620 0 : << ":MaxComputeWorkGroupSizeZ:" << compileResources.MaxComputeWorkGroupSize[2]
621 0 : << ":MaxComputeUniformComponents:" << compileResources.MaxComputeUniformComponents
622 0 : << ":MaxComputeTextureImageUnits:" << compileResources.MaxComputeTextureImageUnits
623 0 : << ":MaxComputeAtomicCounters:" << compileResources.MaxComputeAtomicCounters
624 0 : << ":MaxComputeAtomicCounterBuffers:" << compileResources.MaxComputeAtomicCounterBuffers
625 0 : << ":MaxVertexAtomicCounters:" << compileResources.MaxVertexAtomicCounters
626 0 : << ":MaxFragmentAtomicCounters:" << compileResources.MaxFragmentAtomicCounters
627 0 : << ":MaxCombinedAtomicCounters:" << compileResources.MaxCombinedAtomicCounters
628 0 : << ":MaxAtomicCounterBindings:" << compileResources.MaxAtomicCounterBindings
629 0 : << ":MaxVertexAtomicCounterBuffers:" << compileResources.MaxVertexAtomicCounterBuffers
630 0 : << ":MaxFragmentAtomicCounterBuffers:" << compileResources.MaxFragmentAtomicCounterBuffers
631 0 : << ":MaxCombinedAtomicCounterBuffers:" << compileResources.MaxCombinedAtomicCounterBuffers
632 0 : << ":MaxAtomicCounterBufferSize:" << compileResources.MaxAtomicCounterBufferSize;
633 : // clang-format on
634 :
635 0 : builtInResourcesString = strstream.str();
636 0 : }
637 :
638 0 : void TCompiler::clearResults()
639 : {
640 0 : arrayBoundsClamper.Cleanup();
641 0 : infoSink.info.erase();
642 0 : infoSink.obj.erase();
643 0 : infoSink.debug.erase();
644 :
645 0 : attributes.clear();
646 0 : outputVariables.clear();
647 0 : uniforms.clear();
648 0 : expandedUniforms.clear();
649 0 : varyings.clear();
650 0 : interfaceBlocks.clear();
651 0 : variablesCollected = false;
652 :
653 0 : builtInFunctionEmulator.Cleanup();
654 :
655 0 : nameMap.clear();
656 :
657 0 : mSourcePath = NULL;
658 0 : mTemporaryIndex = 0;
659 0 : }
660 :
661 0 : bool TCompiler::initCallDag(TIntermNode *root)
662 : {
663 0 : mCallDag.clear();
664 :
665 0 : switch (mCallDag.init(root, &infoSink.info))
666 : {
667 : case CallDAG::INITDAG_SUCCESS:
668 0 : return true;
669 : case CallDAG::INITDAG_RECURSION:
670 0 : infoSink.info.prefix(EPrefixError);
671 0 : infoSink.info << "Function recursion detected";
672 0 : return false;
673 : case CallDAG::INITDAG_UNDEFINED:
674 0 : infoSink.info.prefix(EPrefixError);
675 0 : infoSink.info << "Unimplemented function detected";
676 0 : return false;
677 : }
678 :
679 0 : UNREACHABLE();
680 : return true;
681 : }
682 :
683 0 : bool TCompiler::checkCallDepth()
684 : {
685 0 : std::vector<int> depths(mCallDag.size());
686 :
687 0 : for (size_t i = 0; i < mCallDag.size(); i++)
688 : {
689 0 : int depth = 0;
690 0 : auto &record = mCallDag.getRecordFromIndex(i);
691 :
692 0 : for (auto &calleeIndex : record.callees)
693 : {
694 0 : depth = std::max(depth, depths[calleeIndex] + 1);
695 : }
696 :
697 0 : depths[i] = depth;
698 :
699 0 : if (depth >= maxCallStackDepth)
700 : {
701 : // Trace back the function chain to have a meaningful info log.
702 0 : infoSink.info.prefix(EPrefixError);
703 0 : infoSink.info << "Call stack too deep (larger than " << maxCallStackDepth
704 0 : << ") with the following call chain: " << record.name;
705 :
706 0 : int currentFunction = static_cast<int>(i);
707 0 : int currentDepth = depth;
708 :
709 0 : while (currentFunction != -1)
710 : {
711 0 : infoSink.info << " -> " << mCallDag.getRecordFromIndex(currentFunction).name;
712 :
713 0 : int nextFunction = -1;
714 0 : for (auto& calleeIndex : mCallDag.getRecordFromIndex(currentFunction).callees)
715 : {
716 0 : if (depths[calleeIndex] == currentDepth - 1)
717 : {
718 0 : currentDepth--;
719 0 : nextFunction = calleeIndex;
720 : }
721 : }
722 :
723 0 : currentFunction = nextFunction;
724 : }
725 :
726 0 : return false;
727 : }
728 : }
729 :
730 0 : return true;
731 : }
732 :
733 0 : bool TCompiler::tagUsedFunctions()
734 : {
735 : // Search from main, starting from the end of the DAG as it usually is the root.
736 0 : for (size_t i = mCallDag.size(); i-- > 0;)
737 : {
738 0 : if (mCallDag.getRecordFromIndex(i).name == "main(")
739 : {
740 0 : internalTagUsedFunction(i);
741 0 : return true;
742 : }
743 : }
744 :
745 0 : infoSink.info.prefix(EPrefixError);
746 0 : infoSink.info << "Missing main()\n";
747 0 : return false;
748 : }
749 :
750 0 : void TCompiler::internalTagUsedFunction(size_t index)
751 : {
752 0 : if (functionMetadata[index].used)
753 : {
754 0 : return;
755 : }
756 :
757 0 : functionMetadata[index].used = true;
758 :
759 0 : for (int calleeIndex : mCallDag.getRecordFromIndex(index).callees)
760 : {
761 0 : internalTagUsedFunction(calleeIndex);
762 : }
763 : }
764 :
765 : // A predicate for the stl that returns if a top-level node is unused
766 : class TCompiler::UnusedPredicate
767 : {
768 : public:
769 0 : UnusedPredicate(const CallDAG *callDag, const std::vector<FunctionMetadata> *metadatas)
770 0 : : mCallDag(callDag), mMetadatas(metadatas)
771 : {
772 0 : }
773 :
774 0 : bool operator ()(TIntermNode *node)
775 : {
776 0 : const TIntermAggregate *asAggregate = node->getAsAggregate();
777 0 : const TIntermFunctionDefinition *asFunction = node->getAsFunctionDefinition();
778 :
779 0 : const TFunctionSymbolInfo *functionInfo = nullptr;
780 :
781 0 : if (asFunction)
782 : {
783 0 : functionInfo = asFunction->getFunctionSymbolInfo();
784 : }
785 0 : else if (asAggregate)
786 : {
787 0 : if (asAggregate->getOp() == EOpPrototype)
788 : {
789 0 : functionInfo = asAggregate->getFunctionSymbolInfo();
790 : }
791 : }
792 0 : if (functionInfo == nullptr)
793 : {
794 0 : return false;
795 : }
796 :
797 0 : size_t callDagIndex = mCallDag->findIndex(functionInfo);
798 0 : if (callDagIndex == CallDAG::InvalidIndex)
799 : {
800 : // This happens only for unimplemented prototypes which are thus unused
801 0 : ASSERT(asAggregate && asAggregate->getOp() == EOpPrototype);
802 0 : return true;
803 : }
804 :
805 0 : ASSERT(callDagIndex < mMetadatas->size());
806 0 : return !(*mMetadatas)[callDagIndex].used;
807 : }
808 :
809 : private:
810 : const CallDAG *mCallDag;
811 : const std::vector<FunctionMetadata> *mMetadatas;
812 : };
813 :
814 0 : bool TCompiler::pruneUnusedFunctions(TIntermBlock *root)
815 : {
816 0 : UnusedPredicate isUnused(&mCallDag, &functionMetadata);
817 0 : TIntermSequence *sequence = root->getSequence();
818 :
819 0 : if (!sequence->empty())
820 : {
821 0 : sequence->erase(std::remove_if(sequence->begin(), sequence->end(), isUnused), sequence->end());
822 : }
823 :
824 0 : return true;
825 : }
826 :
827 0 : bool TCompiler::validateOutputs(TIntermNode* root)
828 : {
829 0 : ValidateOutputs validateOutputs(getExtensionBehavior(), compileResources.MaxDrawBuffers);
830 0 : root->traverse(&validateOutputs);
831 0 : return (validateOutputs.validateAndCountErrors(infoSink.info) == 0);
832 : }
833 :
834 0 : bool TCompiler::validateLimitations(TIntermNode* root)
835 : {
836 0 : ValidateLimitations validate(shaderType, &infoSink.info);
837 0 : root->traverse(&validate);
838 0 : return validate.numErrors() == 0;
839 : }
840 :
841 0 : bool TCompiler::limitExpressionComplexity(TIntermNode* root)
842 : {
843 0 : TMaxDepthTraverser traverser(maxExpressionComplexity + 1);
844 0 : root->traverse(&traverser);
845 :
846 0 : if (traverser.getMaxDepth() > maxExpressionComplexity)
847 : {
848 0 : infoSink.info << "Expression too complex.";
849 0 : return false;
850 : }
851 :
852 0 : if (!ValidateMaxParameters::validate(root, maxFunctionParameters))
853 : {
854 0 : infoSink.info << "Function has too many parameters.";
855 0 : return false;
856 : }
857 :
858 0 : return true;
859 : }
860 :
861 0 : void TCompiler::collectVariables(TIntermNode* root)
862 : {
863 0 : if (!variablesCollected)
864 : {
865 : sh::CollectVariables collect(&attributes, &outputVariables, &uniforms, &varyings,
866 : &interfaceBlocks, hashFunction, symbolTable,
867 0 : extensionBehavior);
868 0 : root->traverse(&collect);
869 :
870 : // This is for enforcePackingRestriction().
871 0 : sh::ExpandUniforms(uniforms, &expandedUniforms);
872 0 : variablesCollected = true;
873 : }
874 0 : }
875 :
876 0 : bool TCompiler::shouldCollectVariables(ShCompileOptions compileOptions)
877 : {
878 0 : return (compileOptions & SH_VARIABLES) != 0;
879 : }
880 :
881 0 : bool TCompiler::wereVariablesCollected() const
882 : {
883 0 : return variablesCollected;
884 : }
885 :
886 0 : bool TCompiler::enforcePackingRestrictions()
887 : {
888 0 : VariablePacker packer;
889 0 : return packer.CheckVariablesWithinPackingLimits(maxUniformVectors, expandedUniforms);
890 : }
891 :
892 0 : void TCompiler::initializeGLPosition(TIntermNode* root)
893 : {
894 0 : InitVariableList list;
895 0 : sh::ShaderVariable var(GL_FLOAT_VEC4, 0);
896 0 : var.name = "gl_Position";
897 0 : list.push_back(var);
898 0 : InitializeVariables(root, list, symbolTable);
899 0 : }
900 :
901 0 : void TCompiler::useAllMembersInUnusedStandardAndSharedBlocks(TIntermNode *root)
902 : {
903 0 : sh::InterfaceBlockList list;
904 :
905 0 : for (auto block : interfaceBlocks)
906 : {
907 0 : if (!block.staticUse &&
908 0 : (block.layout == sh::BLOCKLAYOUT_STANDARD || block.layout == sh::BLOCKLAYOUT_SHARED))
909 : {
910 0 : list.push_back(block);
911 : }
912 : }
913 :
914 0 : sh::UseInterfaceBlockFields(root, list, symbolTable);
915 0 : }
916 :
917 0 : void TCompiler::initializeOutputVariables(TIntermNode *root)
918 : {
919 0 : InitVariableList list;
920 0 : if (shaderType == GL_VERTEX_SHADER)
921 : {
922 0 : for (auto var : varyings)
923 : {
924 0 : list.push_back(var);
925 : }
926 : }
927 : else
928 : {
929 0 : ASSERT(shaderType == GL_FRAGMENT_SHADER);
930 0 : for (auto var : outputVariables)
931 : {
932 0 : list.push_back(var);
933 : }
934 : }
935 0 : InitializeVariables(root, list, symbolTable);
936 0 : }
937 :
938 0 : const TExtensionBehavior& TCompiler::getExtensionBehavior() const
939 : {
940 0 : return extensionBehavior;
941 : }
942 :
943 0 : const char *TCompiler::getSourcePath() const
944 : {
945 0 : return mSourcePath;
946 : }
947 :
948 0 : const ShBuiltInResources& TCompiler::getResources() const
949 : {
950 0 : return compileResources;
951 : }
952 :
953 0 : const ArrayBoundsClamper& TCompiler::getArrayBoundsClamper() const
954 : {
955 0 : return arrayBoundsClamper;
956 : }
957 :
958 0 : ShArrayIndexClampingStrategy TCompiler::getArrayIndexClampingStrategy() const
959 : {
960 0 : return clampingStrategy;
961 : }
962 :
963 0 : const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
964 : {
965 0 : return builtInFunctionEmulator;
966 : }
967 :
968 0 : void TCompiler::writePragma(ShCompileOptions compileOptions)
969 : {
970 0 : if (!(compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL))
971 : {
972 0 : TInfoSinkBase &sink = infoSink.obj;
973 0 : if (mPragma.stdgl.invariantAll)
974 0 : sink << "#pragma STDGL invariant(all)\n";
975 : }
976 0 : }
977 :
978 0 : bool TCompiler::isVaryingDefined(const char *varyingName)
979 : {
980 0 : ASSERT(variablesCollected);
981 0 : for (size_t ii = 0; ii < varyings.size(); ++ii)
982 : {
983 0 : if (varyings[ii].name == varyingName)
984 : {
985 0 : return true;
986 : }
987 : }
988 :
989 0 : return false;
990 : }
991 :
992 : } // namespace sh
|