1 //
2 // Copyright 2002 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/CallDAG.h"
14 #include "compiler/translator/CollectVariables.h"
15 #include "compiler/translator/Initialize.h"
16 #include "compiler/translator/IsASTDepthBelowLimit.h"
17 #include "compiler/translator/OutputTree.h"
18 #include "compiler/translator/ParseContext.h"
19 #include "compiler/translator/ValidateLimitations.h"
20 #include "compiler/translator/ValidateMaxParameters.h"
21 #include "compiler/translator/ValidateOutputs.h"
22 #include "compiler/translator/ValidateVaryingLocations.h"
23 #include "compiler/translator/VariablePacker.h"
24 #include "compiler/translator/tree_ops/AddAndTrueToLoopCondition.h"
25 #include "compiler/translator/tree_ops/ClampFragDepth.h"
26 #include "compiler/translator/tree_ops/ClampPointSize.h"
27 #include "compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.h"
28 #include "compiler/translator/tree_ops/DeferGlobalInitializers.h"
29 #include "compiler/translator/tree_ops/EmulateGLFragColorBroadcast.h"
30 #include "compiler/translator/tree_ops/EmulateMultiDrawShaderBuiltins.h"
31 #include "compiler/translator/tree_ops/EmulatePrecision.h"
32 #include "compiler/translator/tree_ops/FoldExpressions.h"
33 #include "compiler/translator/tree_ops/InitializeVariables.h"
34 #include "compiler/translator/tree_ops/PruneEmptyCases.h"
35 #include "compiler/translator/tree_ops/PruneNoOps.h"
36 #include "compiler/translator/tree_ops/RegenerateStructNames.h"
37 #include "compiler/translator/tree_ops/RemoveArrayLengthMethod.h"
38 #include "compiler/translator/tree_ops/RemoveInvariantDeclaration.h"
39 #include "compiler/translator/tree_ops/RemovePow.h"
40 #include "compiler/translator/tree_ops/RemoveUnreferencedVariables.h"
41 #include "compiler/translator/tree_ops/RewriteDoWhile.h"
42 #include "compiler/translator/tree_ops/RewriteRepeatedAssignToSwizzled.h"
43 #include "compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.h"
44 #include "compiler/translator/tree_ops/SeparateDeclarations.h"
45 #include "compiler/translator/tree_ops/SimplifyLoopConditions.h"
46 #include "compiler/translator/tree_ops/SplitSequenceOperator.h"
47 #include "compiler/translator/tree_ops/UnfoldShortCircuitAST.h"
48 #include "compiler/translator/tree_ops/UseInterfaceBlockFields.h"
49 #include "compiler/translator/tree_ops/VectorizeVectorScalarArithmetic.h"
50 #include "compiler/translator/tree_util/BuiltIn_autogen.h"
51 #include "compiler/translator/tree_util/IntermNodePatternMatcher.h"
52 #include "compiler/translator/tree_util/ReplaceShadowingVariables.h"
53 #include "compiler/translator/util.h"
54 #include "third_party/compiler/ArrayBoundsClamper.h"
55
56 namespace sh
57 {
58
59 namespace
60 {
61
62 #if defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT)
DumpFuzzerCase(char const * const * shaderStrings,size_t numStrings,uint32_t type,uint32_t spec,uint32_t output,uint64_t options)63 void DumpFuzzerCase(char const *const *shaderStrings,
64 size_t numStrings,
65 uint32_t type,
66 uint32_t spec,
67 uint32_t output,
68 uint64_t options)
69 {
70 static int fileIndex = 0;
71
72 std::ostringstream o = sh::InitializeStream<std::ostringstream>();
73 o << "corpus/" << fileIndex++ << ".sample";
74 std::string s = o.str();
75
76 // Must match the input format of the fuzzer
77 FILE *f = fopen(s.c_str(), "w");
78 fwrite(&type, sizeof(type), 1, f);
79 fwrite(&spec, sizeof(spec), 1, f);
80 fwrite(&output, sizeof(output), 1, f);
81 fwrite(&options, sizeof(options), 1, f);
82
83 char zero[128 - 20] = {0};
84 fwrite(&zero, 128 - 20, 1, f);
85
86 for (size_t i = 0; i < numStrings; i++)
87 {
88 fwrite(shaderStrings[i], sizeof(char), strlen(shaderStrings[i]), f);
89 }
90 fwrite(&zero, 1, 1, f);
91
92 fclose(f);
93 }
94 #endif // defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT)
95 } // anonymous namespace
96
IsGLSL130OrNewer(ShShaderOutput output)97 bool IsGLSL130OrNewer(ShShaderOutput output)
98 {
99 return (output == SH_GLSL_130_OUTPUT || output == SH_GLSL_140_OUTPUT ||
100 output == SH_GLSL_150_CORE_OUTPUT || output == SH_GLSL_330_CORE_OUTPUT ||
101 output == SH_GLSL_400_CORE_OUTPUT || output == SH_GLSL_410_CORE_OUTPUT ||
102 output == SH_GLSL_420_CORE_OUTPUT || output == SH_GLSL_430_CORE_OUTPUT ||
103 output == SH_GLSL_440_CORE_OUTPUT || output == SH_GLSL_450_CORE_OUTPUT);
104 }
105
IsGLSL420OrNewer(ShShaderOutput output)106 bool IsGLSL420OrNewer(ShShaderOutput output)
107 {
108 return (output == SH_GLSL_420_CORE_OUTPUT || output == SH_GLSL_430_CORE_OUTPUT ||
109 output == SH_GLSL_440_CORE_OUTPUT || output == SH_GLSL_450_CORE_OUTPUT);
110 }
111
IsGLSL410OrOlder(ShShaderOutput output)112 bool IsGLSL410OrOlder(ShShaderOutput output)
113 {
114 return (output == SH_GLSL_130_OUTPUT || output == SH_GLSL_140_OUTPUT ||
115 output == SH_GLSL_150_CORE_OUTPUT || output == SH_GLSL_330_CORE_OUTPUT ||
116 output == SH_GLSL_400_CORE_OUTPUT || output == SH_GLSL_410_CORE_OUTPUT);
117 }
118
RemoveInvariant(sh::GLenum shaderType,int shaderVersion,ShShaderOutput outputType,ShCompileOptions compileOptions)119 bool RemoveInvariant(sh::GLenum shaderType,
120 int shaderVersion,
121 ShShaderOutput outputType,
122 ShCompileOptions compileOptions)
123 {
124 if (shaderType == GL_FRAGMENT_SHADER && IsGLSL420OrNewer(outputType))
125 return true;
126
127 if ((compileOptions & SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3) != 0 &&
128 shaderVersion >= 300 && shaderType == GL_VERTEX_SHADER)
129 return true;
130
131 return false;
132 }
133
GetGlobalMaxTokenSize(ShShaderSpec spec)134 size_t GetGlobalMaxTokenSize(ShShaderSpec spec)
135 {
136 // WebGL defines a max token length of 256, while ES2 leaves max token
137 // size undefined. ES3 defines a max size of 1024 characters.
138 switch (spec)
139 {
140 case SH_WEBGL_SPEC:
141 return 256;
142 default:
143 return 1024;
144 }
145 }
146
GetMaxUniformVectorsForShaderType(GLenum shaderType,const ShBuiltInResources & resources)147 int GetMaxUniformVectorsForShaderType(GLenum shaderType, const ShBuiltInResources &resources)
148 {
149 switch (shaderType)
150 {
151 case GL_VERTEX_SHADER:
152 return resources.MaxVertexUniformVectors;
153 case GL_FRAGMENT_SHADER:
154 return resources.MaxFragmentUniformVectors;
155
156 // TODO (jiawei.shao@intel.com): check if we need finer-grained component counting
157 case GL_COMPUTE_SHADER:
158 return resources.MaxComputeUniformComponents / 4;
159 case GL_GEOMETRY_SHADER_EXT:
160 return resources.MaxGeometryUniformComponents / 4;
161 default:
162 UNREACHABLE();
163 return -1;
164 }
165 }
166
167 namespace
168 {
169
170 class TScopedPoolAllocator
171 {
172 public:
TScopedPoolAllocator(angle::PoolAllocator * allocator)173 TScopedPoolAllocator(angle::PoolAllocator *allocator) : mAllocator(allocator)
174 {
175 mAllocator->push();
176 SetGlobalPoolAllocator(mAllocator);
177 }
~TScopedPoolAllocator()178 ~TScopedPoolAllocator()
179 {
180 SetGlobalPoolAllocator(nullptr);
181 mAllocator->pop();
182 }
183
184 private:
185 angle::PoolAllocator *mAllocator;
186 };
187
188 class TScopedSymbolTableLevel
189 {
190 public:
TScopedSymbolTableLevel(TSymbolTable * table)191 TScopedSymbolTableLevel(TSymbolTable *table) : mTable(table)
192 {
193 ASSERT(mTable->isEmpty());
194 mTable->push();
195 }
~TScopedSymbolTableLevel()196 ~TScopedSymbolTableLevel()
197 {
198 while (!mTable->isEmpty())
199 mTable->pop();
200 }
201
202 private:
203 TSymbolTable *mTable;
204 };
205
GetMaxShaderVersionForSpec(ShShaderSpec spec)206 int GetMaxShaderVersionForSpec(ShShaderSpec spec)
207 {
208 switch (spec)
209 {
210 case SH_GLES2_SPEC:
211 case SH_WEBGL_SPEC:
212 return 100;
213 case SH_GLES3_SPEC:
214 case SH_WEBGL2_SPEC:
215 return 300;
216 case SH_GLES3_1_SPEC:
217 case SH_WEBGL3_SPEC:
218 return 310;
219 case SH_GL_CORE_SPEC:
220 case SH_GL_COMPATIBILITY_SPEC:
221 return 460;
222 default:
223 UNREACHABLE();
224 return 0;
225 }
226 }
227
ValidateFragColorAndFragData(GLenum shaderType,int shaderVersion,const TSymbolTable & symbolTable,TDiagnostics * diagnostics)228 bool ValidateFragColorAndFragData(GLenum shaderType,
229 int shaderVersion,
230 const TSymbolTable &symbolTable,
231 TDiagnostics *diagnostics)
232 {
233 if (shaderVersion > 100 || shaderType != GL_FRAGMENT_SHADER)
234 {
235 return true;
236 }
237
238 bool usesFragColor = false;
239 bool usesFragData = false;
240 // This validation is a bit stricter than the spec - it's only an error to write to
241 // both FragData and FragColor. But because it's better not to have reads from undefined
242 // variables, we always return an error if they are both referenced, rather than only if they
243 // are written.
244 if (symbolTable.isStaticallyUsed(*BuiltInVariable::gl_FragColor()) ||
245 symbolTable.isStaticallyUsed(*BuiltInVariable::gl_SecondaryFragColorEXT()))
246 {
247 usesFragColor = true;
248 }
249 // Extension variables may not always be initialized (saves some time at symbol table init).
250 bool secondaryFragDataUsed =
251 symbolTable.gl_SecondaryFragDataEXT() != nullptr &&
252 symbolTable.isStaticallyUsed(*symbolTable.gl_SecondaryFragDataEXT());
253 if (symbolTable.isStaticallyUsed(*symbolTable.gl_FragData()) || secondaryFragDataUsed)
254 {
255 usesFragData = true;
256 }
257 if (usesFragColor && usesFragData)
258 {
259 const char *errorMessage = "cannot use both gl_FragData and gl_FragColor";
260 if (symbolTable.isStaticallyUsed(*BuiltInVariable::gl_SecondaryFragColorEXT()) ||
261 secondaryFragDataUsed)
262 {
263 errorMessage =
264 "cannot use both output variable sets (gl_FragData, gl_SecondaryFragDataEXT)"
265 " and (gl_FragColor, gl_SecondaryFragColorEXT)";
266 }
267 diagnostics->globalError(errorMessage);
268 return false;
269 }
270 return true;
271 }
272
273 } // namespace
274
TShHandleBase()275 TShHandleBase::TShHandleBase()
276 {
277 allocator.push();
278 SetGlobalPoolAllocator(&allocator);
279 }
280
~TShHandleBase()281 TShHandleBase::~TShHandleBase()
282 {
283 SetGlobalPoolAllocator(nullptr);
284 allocator.popAll();
285 }
286
TCompiler(sh::GLenum type,ShShaderSpec spec,ShShaderOutput output)287 TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
288 : mVariablesCollected(false),
289 mGLPositionInitialized(false),
290 mShaderType(type),
291 mShaderSpec(spec),
292 mOutputType(output),
293 mBuiltInFunctionEmulator(),
294 mDiagnostics(mInfoSink.info),
295 mSourcePath(nullptr),
296 mComputeShaderLocalSizeDeclared(false),
297 mComputeShaderLocalSize(1),
298 mGeometryShaderMaxVertices(-1),
299 mGeometryShaderInvocations(0),
300 mGeometryShaderInputPrimitiveType(EptUndefined),
301 mGeometryShaderOutputPrimitiveType(EptUndefined)
302 {}
303
~TCompiler()304 TCompiler::~TCompiler() {}
305
shouldRunLoopAndIndexingValidation(ShCompileOptions compileOptions) const306 bool TCompiler::shouldRunLoopAndIndexingValidation(ShCompileOptions compileOptions) const
307 {
308 // If compiling an ESSL 1.00 shader for WebGL, or if its been requested through the API,
309 // validate loop and indexing as well (to verify that the shader only uses minimal functionality
310 // of ESSL 1.00 as in Appendix A of the spec).
311 return (IsWebGLBasedSpec(mShaderSpec) && mShaderVersion == 100) ||
312 (compileOptions & SH_VALIDATE_LOOP_INDEXING);
313 }
314
Init(const ShBuiltInResources & resources)315 bool TCompiler::Init(const ShBuiltInResources &resources)
316 {
317 SetGlobalPoolAllocator(&allocator);
318
319 // Generate built-in symbol table.
320 if (!initBuiltInSymbolTable(resources))
321 return false;
322
323 mResources = resources;
324 setResourceString();
325
326 InitExtensionBehavior(resources, mExtensionBehavior);
327 mArrayBoundsClamper.SetClampingStrategy(resources.ArrayIndexClampingStrategy);
328 return true;
329 }
330
compileTreeForTesting(const char * const shaderStrings[],size_t numStrings,ShCompileOptions compileOptions)331 TIntermBlock *TCompiler::compileTreeForTesting(const char *const shaderStrings[],
332 size_t numStrings,
333 ShCompileOptions compileOptions)
334 {
335 return compileTreeImpl(shaderStrings, numStrings, compileOptions);
336 }
337
compileTreeImpl(const char * const shaderStrings[],size_t numStrings,const ShCompileOptions compileOptions)338 TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
339 size_t numStrings,
340 const ShCompileOptions compileOptions)
341 {
342 clearResults();
343
344 ASSERT(numStrings > 0);
345 ASSERT(GetGlobalPoolAllocator());
346
347 // Reset the extension behavior for each compilation unit.
348 ResetExtensionBehavior(mExtensionBehavior);
349
350 // If gl_DrawID is not supported, remove it from the available extensions
351 // Currently we only allow emulation of gl_DrawID
352 const bool glDrawIDSupported = (compileOptions & SH_EMULATE_GL_DRAW_ID) != 0u;
353 if (!glDrawIDSupported)
354 {
355 auto it = mExtensionBehavior.find(TExtension::ANGLE_multi_draw);
356 if (it != mExtensionBehavior.end())
357 {
358 mExtensionBehavior.erase(it);
359 }
360 }
361
362 const bool glBaseVertexBaseInstanceSupported =
363 (compileOptions & SH_EMULATE_GL_BASE_VERTEX_BASE_INSTANCE) != 0u;
364 if (!glBaseVertexBaseInstanceSupported)
365 {
366 auto it = mExtensionBehavior.find(TExtension::ANGLE_base_vertex_base_instance);
367 if (it != mExtensionBehavior.end())
368 {
369 mExtensionBehavior.erase(it);
370 }
371 }
372
373 // First string is path of source file if flag is set. The actual source follows.
374 size_t firstSource = 0;
375 if (compileOptions & SH_SOURCE_PATH)
376 {
377 mSourcePath = shaderStrings[0];
378 ++firstSource;
379 }
380
381 TParseContext parseContext(mSymbolTable, mExtensionBehavior, mShaderType, mShaderSpec,
382 compileOptions, !IsDesktopGLSpec(mShaderSpec), &mDiagnostics,
383 getResources());
384
385 parseContext.setFragmentPrecisionHighOnESSL1(mResources.FragmentPrecisionHigh == 1);
386
387 // We preserve symbols at the built-in level from compile-to-compile.
388 // Start pushing the user-defined symbols at global level.
389 TScopedSymbolTableLevel globalLevel(&mSymbolTable);
390 ASSERT(mSymbolTable.atGlobalLevel());
391
392 // Parse shader.
393 if (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], nullptr,
394 &parseContext) != 0)
395 {
396 return nullptr;
397 }
398
399 if (parseContext.getTreeRoot() == nullptr)
400 {
401 return nullptr;
402 }
403
404 setASTMetadata(parseContext);
405
406 if (!checkShaderVersion(&parseContext))
407 {
408 return nullptr;
409 }
410
411 TIntermBlock *root = parseContext.getTreeRoot();
412 if (!checkAndSimplifyAST(root, parseContext, compileOptions))
413 {
414 return nullptr;
415 }
416
417 return root;
418 }
419
checkShaderVersion(TParseContext * parseContext)420 bool TCompiler::checkShaderVersion(TParseContext *parseContext)
421 {
422 if (GetMaxShaderVersionForSpec(mShaderSpec) < mShaderVersion)
423 {
424 mDiagnostics.globalError("unsupported shader version");
425 return false;
426 }
427
428 ASSERT(parseContext);
429 switch (mShaderType)
430 {
431 case GL_COMPUTE_SHADER:
432 if (mShaderVersion < 310)
433 {
434 mDiagnostics.globalError("Compute shader is not supported in this shader version.");
435 return false;
436 }
437 break;
438
439 case GL_GEOMETRY_SHADER_EXT:
440 if (mShaderVersion < 310)
441 {
442 mDiagnostics.globalError(
443 "Geometry shader is not supported in this shader version.");
444 return false;
445 }
446 else
447 {
448 ASSERT(mShaderVersion == 310);
449 if (!parseContext->checkCanUseExtension(sh::TSourceLoc(),
450 TExtension::EXT_geometry_shader))
451 {
452 return false;
453 }
454 }
455 break;
456
457 default:
458 break;
459 }
460
461 return true;
462 }
463
setASTMetadata(const TParseContext & parseContext)464 void TCompiler::setASTMetadata(const TParseContext &parseContext)
465 {
466 mShaderVersion = parseContext.getShaderVersion();
467
468 mPragma = parseContext.pragma();
469 mSymbolTable.setGlobalInvariant(mPragma.stdgl.invariantAll);
470
471 mComputeShaderLocalSizeDeclared = parseContext.isComputeShaderLocalSizeDeclared();
472 mComputeShaderLocalSize = parseContext.getComputeShaderLocalSize();
473
474 mNumViews = parseContext.getNumViews();
475
476 if (mShaderType == GL_GEOMETRY_SHADER_EXT)
477 {
478 mGeometryShaderInputPrimitiveType = parseContext.getGeometryShaderInputPrimitiveType();
479 mGeometryShaderOutputPrimitiveType = parseContext.getGeometryShaderOutputPrimitiveType();
480 mGeometryShaderMaxVertices = parseContext.getGeometryShaderMaxVertices();
481 mGeometryShaderInvocations = parseContext.getGeometryShaderInvocations();
482 }
483 }
484
checkAndSimplifyAST(TIntermBlock * root,const TParseContext & parseContext,ShCompileOptions compileOptions)485 bool TCompiler::checkAndSimplifyAST(TIntermBlock *root,
486 const TParseContext &parseContext,
487 ShCompileOptions compileOptions)
488 {
489 // Disallow expressions deemed too complex.
490 if ((compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY) && !limitExpressionComplexity(root))
491 {
492 return false;
493 }
494
495 if (shouldRunLoopAndIndexingValidation(compileOptions) &&
496 !ValidateLimitations(root, mShaderType, &mSymbolTable, &mDiagnostics))
497 {
498 return false;
499 }
500
501 if (!ValidateFragColorAndFragData(mShaderType, mShaderVersion, mSymbolTable, &mDiagnostics))
502 {
503 return false;
504 }
505
506 // Fold expressions that could not be folded before validation that was done as a part of
507 // parsing.
508 FoldExpressions(root, &mDiagnostics);
509 // Folding should only be able to generate warnings.
510 ASSERT(mDiagnostics.numErrors() == 0);
511 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
512 {
513 return false;
514 }
515
516 // We prune no-ops to work around driver bugs and to keep AST processing and output simple.
517 // The following kinds of no-ops are pruned:
518 // 1. Empty declarations "int;".
519 // 2. Literal statements: "1.0;". The ESSL output doesn't define a default precision
520 // for float, so float literal statements would end up with no precision which is
521 // invalid ESSL.
522 // After this empty declarations are not allowed in the AST.
523 PruneNoOps(root, &mSymbolTable);
524 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
525 {
526 return false;
527 }
528
529 // Create the function DAG and check there is no recursion
530 if (!initCallDag(root))
531 {
532 return false;
533 }
534
535 if ((compileOptions & SH_LIMIT_CALL_STACK_DEPTH) && !checkCallDepth())
536 {
537 return false;
538 }
539
540 // Checks which functions are used and if "main" exists
541 mFunctionMetadata.clear();
542 mFunctionMetadata.resize(mCallDag.size());
543 if (!tagUsedFunctions())
544 {
545 return false;
546 }
547
548 if (!(compileOptions & SH_DONT_PRUNE_UNUSED_FUNCTIONS))
549 {
550 pruneUnusedFunctions(root);
551 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
552 {
553 return false;
554 }
555 }
556 if (IsSpecWithFunctionBodyNewScope(mShaderSpec, mShaderVersion))
557 {
558 ReplaceShadowingVariables(root, &mSymbolTable);
559 }
560
561 if (mShaderVersion >= 310 && !ValidateVaryingLocations(root, &mDiagnostics, mShaderType))
562 {
563 return false;
564 }
565
566 if (mShaderVersion >= 300 && mShaderType == GL_FRAGMENT_SHADER &&
567 !ValidateOutputs(root, getExtensionBehavior(), mResources.MaxDrawBuffers, &mDiagnostics))
568 {
569 return false;
570 }
571
572 // Fail compilation if precision emulation not supported.
573 if (getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision &&
574 !EmulatePrecision::SupportedInLanguage(mOutputType))
575 {
576 mDiagnostics.globalError("Precision emulation not supported for this output type.");
577 return false;
578 }
579
580 // Clamping uniform array bounds needs to happen after validateLimitations pass.
581 if (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS)
582 {
583 mArrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root);
584 }
585
586 if ((compileOptions & SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW) &&
587 (parseContext.isExtensionEnabled(TExtension::OVR_multiview2) ||
588 parseContext.isExtensionEnabled(TExtension::OVR_multiview)) &&
589 getShaderType() != GL_COMPUTE_SHADER)
590 {
591 DeclareAndInitBuiltinsForInstancedMultiview(root, mNumViews, mShaderType, compileOptions,
592 mOutputType, &mSymbolTable);
593 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
594 {
595 return false;
596 }
597 }
598
599 // This pass might emit short circuits so keep it before the short circuit unfolding
600 if (compileOptions & SH_REWRITE_DO_WHILE_LOOPS)
601 {
602 RewriteDoWhile(root, &mSymbolTable);
603 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
604 {
605 return false;
606 }
607 }
608
609 if (compileOptions & SH_ADD_AND_TRUE_TO_LOOP_CONDITION)
610 {
611 AddAndTrueToLoopCondition(root);
612 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
613 {
614 return false;
615 }
616 }
617
618 if (compileOptions & SH_UNFOLD_SHORT_CIRCUIT)
619 {
620 UnfoldShortCircuitAST(root);
621 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
622 {
623 return false;
624 }
625 }
626
627 if (compileOptions & SH_REMOVE_POW_WITH_CONSTANT_EXPONENT)
628 {
629 RemovePow(root, &mSymbolTable);
630 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
631 {
632 return false;
633 }
634 }
635
636 if (compileOptions & SH_REGENERATE_STRUCT_NAMES)
637 {
638 RegenerateStructNames gen(&mSymbolTable);
639 root->traverse(&gen);
640 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
641 {
642 return false;
643 }
644 }
645
646 if (mShaderType == GL_VERTEX_SHADER &&
647 IsExtensionEnabled(mExtensionBehavior, TExtension::ANGLE_multi_draw))
648 {
649 if ((compileOptions & SH_EMULATE_GL_DRAW_ID) != 0u)
650 {
651 EmulateGLDrawID(root, &mSymbolTable, &mUniforms,
652 shouldCollectVariables(compileOptions));
653 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
654 {
655 return false;
656 }
657 }
658 }
659
660 if (mShaderType == GL_VERTEX_SHADER &&
661 IsExtensionEnabled(mExtensionBehavior, TExtension::ANGLE_base_vertex_base_instance))
662 {
663 if ((compileOptions & SH_EMULATE_GL_BASE_VERTEX_BASE_INSTANCE) != 0u)
664 {
665 EmulateGLBaseVertex(root, &mSymbolTable, &mUniforms,
666 shouldCollectVariables(compileOptions));
667 EmulateGLBaseInstance(root, &mSymbolTable, &mUniforms,
668 shouldCollectVariables(compileOptions));
669 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
670 {
671 return false;
672 }
673 }
674 }
675
676 if (mShaderType == GL_FRAGMENT_SHADER && mShaderVersion == 100 && mResources.EXT_draw_buffers &&
677 mResources.MaxDrawBuffers > 1 &&
678 IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers))
679 {
680 EmulateGLFragColorBroadcast(root, mResources.MaxDrawBuffers, &mOutputVariables,
681 &mSymbolTable, mShaderVersion);
682 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
683 {
684 return false;
685 }
686 }
687
688 int simplifyScalarized = (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS)
689 ? IntermNodePatternMatcher::kScalarizedVecOrMatConstructor
690 : 0;
691
692 // Split multi declarations and remove calls to array length().
693 // Note that SimplifyLoopConditions needs to be run before any other AST transformations
694 // that may need to generate new statements from loop conditions or loop expressions.
695 SimplifyLoopConditions(root,
696 IntermNodePatternMatcher::kMultiDeclaration |
697 IntermNodePatternMatcher::kArrayLengthMethod | simplifyScalarized,
698 &getSymbolTable());
699 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
700 {
701 return false;
702 }
703
704 // Note that separate declarations need to be run before other AST transformations that
705 // generate new statements from expressions.
706 SeparateDeclarations(root);
707 mValidateASTOptions.validateMultiDeclarations = true;
708 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
709 {
710 return false;
711 }
712
713 SplitSequenceOperator(root, IntermNodePatternMatcher::kArrayLengthMethod | simplifyScalarized,
714 &getSymbolTable());
715 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
716 {
717 return false;
718 }
719
720 RemoveArrayLengthMethod(root);
721 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
722 {
723 return false;
724 }
725
726 RemoveUnreferencedVariables(root, &mSymbolTable);
727 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
728 {
729 return false;
730 }
731
732 // In case the last case inside a switch statement is a certain type of no-op, GLSL compilers in
733 // drivers may not accept it. In this case we clean up the dead code from the end of switch
734 // statements. This is also required because PruneNoOps or RemoveUnreferencedVariables may have
735 // left switch statements that only contained an empty declaration inside the final case in an
736 // invalid state. Relies on that PruneNoOps and RemoveUnreferencedVariables have already been
737 // run.
738 PruneEmptyCases(root);
739 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
740 {
741 return false;
742 }
743
744 // Built-in function emulation needs to happen after validateLimitations pass.
745 // TODO(jmadill): Remove global pool allocator.
746 GetGlobalPoolAllocator()->lock();
747 initBuiltInFunctionEmulator(&mBuiltInFunctionEmulator, compileOptions);
748 GetGlobalPoolAllocator()->unlock();
749 mBuiltInFunctionEmulator.markBuiltInFunctionsForEmulation(root);
750
751 bool highPrecisionSupported = mShaderVersion > 100 || mShaderType != GL_FRAGMENT_SHADER ||
752 mResources.FragmentPrecisionHigh == 1;
753 if (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS)
754 {
755 ScalarizeVecAndMatConstructorArgs(root, mShaderType, highPrecisionSupported, &mSymbolTable);
756 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
757 {
758 return false;
759 }
760 }
761
762 if (shouldCollectVariables(compileOptions))
763 {
764 ASSERT(!mVariablesCollected);
765 CollectVariables(root, &mAttributes, &mOutputVariables, &mUniforms, &mInputVaryings,
766 &mOutputVaryings, &mUniformBlocks, &mShaderStorageBlocks, &mInBlocks,
767 mResources.HashFunction, &mSymbolTable, mShaderType, mExtensionBehavior);
768 collectInterfaceBlocks();
769 mVariablesCollected = true;
770 if (compileOptions & SH_USE_UNUSED_STANDARD_SHARED_BLOCKS)
771 {
772 useAllMembersInUnusedStandardAndSharedBlocks(root);
773 }
774 if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS)
775 {
776 int maxUniformVectors = GetMaxUniformVectorsForShaderType(mShaderType, mResources);
777 // Returns true if, after applying the packing rules in the GLSL ES 1.00.17 spec
778 // Appendix A, section 7, the shader does not use too many uniforms.
779 if (!CheckVariablesInPackingLimits(maxUniformVectors, mUniforms))
780 {
781 mDiagnostics.globalError("too many uniforms");
782 return false;
783 }
784 }
785 if ((compileOptions & SH_INIT_OUTPUT_VARIABLES) && (mShaderType != GL_COMPUTE_SHADER))
786 {
787 initializeOutputVariables(root);
788 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
789 {
790 return false;
791 }
792 }
793 }
794
795 // Removing invariant declarations must be done after collecting variables.
796 // Otherwise, built-in invariant declarations don't apply.
797 if (RemoveInvariant(mShaderType, mShaderVersion, mOutputType, compileOptions))
798 {
799 RemoveInvariantDeclaration(root);
800 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
801 {
802 return false;
803 }
804 }
805
806 // gl_Position is always written in compatibility output mode.
807 // It may have been already initialized among other output variables, in that case we don't
808 // need to initialize it twice.
809 if (mShaderType == GL_VERTEX_SHADER && !mGLPositionInitialized &&
810 ((compileOptions & SH_INIT_GL_POSITION) || (mOutputType == SH_GLSL_COMPATIBILITY_OUTPUT)))
811 {
812 initializeGLPosition(root);
813 mGLPositionInitialized = true;
814 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
815 {
816 return false;
817 }
818 }
819
820 // DeferGlobalInitializers needs to be run before other AST transformations that generate new
821 // statements from expressions. But it's fine to run DeferGlobalInitializers after the above
822 // SplitSequenceOperator and RemoveArrayLengthMethod since they only have an effect on the AST
823 // on ESSL >= 3.00, and the initializers that need to be deferred can only exist in ESSL < 3.00.
824 bool initializeLocalsAndGlobals =
825 (compileOptions & SH_INITIALIZE_UNINITIALIZED_LOCALS) && !IsOutputHLSL(getOutputType());
826 bool canUseLoopsToInitialize = !(compileOptions & SH_DONT_USE_LOOPS_TO_INITIALIZE_VARIABLES);
827 DeferGlobalInitializers(root, initializeLocalsAndGlobals, canUseLoopsToInitialize,
828 highPrecisionSupported, &mSymbolTable);
829 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
830 {
831 return false;
832 }
833
834 if (initializeLocalsAndGlobals)
835 {
836 // Initialize uninitialized local variables.
837 // In some cases initializing can generate extra statements in the parent block, such as
838 // when initializing nameless structs or initializing arrays in ESSL 1.00. In that case
839 // we need to first simplify loop conditions. We've already separated declarations
840 // earlier, which is also required. If we don't follow the Appendix A limitations, loop
841 // init statements can declare arrays or nameless structs and have multiple
842 // declarations.
843
844 if (!shouldRunLoopAndIndexingValidation(compileOptions))
845 {
846 SimplifyLoopConditions(root,
847 IntermNodePatternMatcher::kArrayDeclaration |
848 IntermNodePatternMatcher::kNamelessStructDeclaration,
849 &getSymbolTable());
850 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
851 {
852 return false;
853 }
854 }
855
856 InitializeUninitializedLocals(root, getShaderVersion(), canUseLoopsToInitialize,
857 highPrecisionSupported, &getSymbolTable());
858 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
859 {
860 return false;
861 }
862 }
863
864 if (getShaderType() == GL_VERTEX_SHADER && (compileOptions & SH_CLAMP_POINT_SIZE))
865 {
866 ClampPointSize(root, mResources.MaxPointSize, &getSymbolTable());
867 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
868 {
869 return false;
870 }
871 }
872
873 if (getShaderType() == GL_FRAGMENT_SHADER && (compileOptions & SH_CLAMP_FRAG_DEPTH))
874 {
875 ClampFragDepth(root, &getSymbolTable());
876 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
877 {
878 return false;
879 }
880 }
881
882 if (compileOptions & SH_REWRITE_REPEATED_ASSIGN_TO_SWIZZLED)
883 {
884 sh::RewriteRepeatedAssignToSwizzled(root);
885 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
886 {
887 return false;
888 }
889 }
890
891 if (compileOptions & SH_REWRITE_VECTOR_SCALAR_ARITHMETIC)
892 {
893 VectorizeVectorScalarArithmetic(root, &getSymbolTable());
894 if (!ValidateAST(root, &mDiagnostics, mValidateASTOptions))
895 {
896 return false;
897 }
898 }
899
900 return true;
901 }
902
compile(const char * const shaderStrings[],size_t numStrings,ShCompileOptions compileOptionsIn)903 bool TCompiler::compile(const char *const shaderStrings[],
904 size_t numStrings,
905 ShCompileOptions compileOptionsIn)
906 {
907 #if defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT)
908 DumpFuzzerCase(shaderStrings, numStrings, mShaderType, mShaderSpec, mOutputType,
909 compileOptionsIn);
910 #endif // defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT)
911
912 if (numStrings == 0)
913 return true;
914
915 ShCompileOptions compileOptions = compileOptionsIn;
916
917 // Apply key workarounds.
918 if (shouldFlattenPragmaStdglInvariantAll())
919 {
920 // This should be harmless to do in all cases, but for the moment, do it only conditionally.
921 compileOptions |= SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL;
922 }
923
924 TScopedPoolAllocator scopedAlloc(&allocator);
925 TIntermBlock *root = compileTreeImpl(shaderStrings, numStrings, compileOptions);
926
927 if (root)
928 {
929 if (compileOptions & SH_INTERMEDIATE_TREE)
930 OutputTree(root, mInfoSink.info);
931
932 if (compileOptions & SH_OBJECT_CODE)
933 {
934 PerformanceDiagnostics perfDiagnostics(&mDiagnostics);
935 translate(root, compileOptions, &perfDiagnostics);
936 }
937
938 if (mShaderType == GL_VERTEX_SHADER)
939 {
940 bool lookForDrawID =
941 IsExtensionEnabled(mExtensionBehavior, TExtension::ANGLE_multi_draw) &&
942 ((compileOptions & SH_EMULATE_GL_DRAW_ID) != 0u);
943 bool lookForBaseVertexBaseInstance =
944 IsExtensionEnabled(mExtensionBehavior,
945 TExtension::ANGLE_base_vertex_base_instance) &&
946 ((compileOptions & SH_EMULATE_GL_BASE_VERTEX_BASE_INSTANCE) != 0u);
947
948 if (lookForDrawID || lookForBaseVertexBaseInstance)
949 {
950 for (auto &uniform : mUniforms)
951 {
952 if (lookForDrawID && uniform.name == "angle_DrawID" &&
953 uniform.mappedName == "angle_DrawID")
954 {
955 uniform.name = "gl_DrawID";
956 }
957 else if (lookForBaseVertexBaseInstance && uniform.name == "angle_BaseVertex" &&
958 uniform.mappedName == "angle_BaseVertex")
959 {
960 uniform.name = "gl_BaseVertex";
961 }
962 else if (lookForBaseVertexBaseInstance &&
963 uniform.name == "angle_BaseInstance" &&
964 uniform.mappedName == "angle_BaseInstance")
965 {
966 uniform.name = "gl_BaseInstance";
967 }
968 }
969 }
970 }
971
972 // The IntermNode tree doesn't need to be deleted here, since the
973 // memory will be freed in a big chunk by the PoolAllocator.
974 return true;
975 }
976 return false;
977 }
978
initBuiltInSymbolTable(const ShBuiltInResources & resources)979 bool TCompiler::initBuiltInSymbolTable(const ShBuiltInResources &resources)
980 {
981 if (resources.MaxDrawBuffers < 1)
982 {
983 return false;
984 }
985 if (resources.EXT_blend_func_extended && resources.MaxDualSourceDrawBuffers < 1)
986 {
987 return false;
988 }
989
990 mSymbolTable.initializeBuiltIns(mShaderType, mShaderSpec, resources);
991
992 return true;
993 }
994
setResourceString()995 void TCompiler::setResourceString()
996 {
997 std::ostringstream strstream = sh::InitializeStream<std::ostringstream>();
998
999 // clang-format off
1000 strstream << ":MaxVertexAttribs:" << mResources.MaxVertexAttribs
1001 << ":MaxVertexUniformVectors:" << mResources.MaxVertexUniformVectors
1002 << ":MaxVaryingVectors:" << mResources.MaxVaryingVectors
1003 << ":MaxVertexTextureImageUnits:" << mResources.MaxVertexTextureImageUnits
1004 << ":MaxCombinedTextureImageUnits:" << mResources.MaxCombinedTextureImageUnits
1005 << ":MaxTextureImageUnits:" << mResources.MaxTextureImageUnits
1006 << ":MaxFragmentUniformVectors:" << mResources.MaxFragmentUniformVectors
1007 << ":MaxDrawBuffers:" << mResources.MaxDrawBuffers
1008 << ":OES_standard_derivatives:" << mResources.OES_standard_derivatives
1009 << ":OES_EGL_image_external:" << mResources.OES_EGL_image_external
1010 << ":OES_EGL_image_external_essl3:" << mResources.OES_EGL_image_external_essl3
1011 << ":NV_EGL_stream_consumer_external:" << mResources.NV_EGL_stream_consumer_external
1012 << ":ARB_texture_rectangle:" << mResources.ARB_texture_rectangle
1013 << ":EXT_draw_buffers:" << mResources.EXT_draw_buffers
1014 << ":FragmentPrecisionHigh:" << mResources.FragmentPrecisionHigh
1015 << ":MaxExpressionComplexity:" << mResources.MaxExpressionComplexity
1016 << ":MaxCallStackDepth:" << mResources.MaxCallStackDepth
1017 << ":MaxFunctionParameters:" << mResources.MaxFunctionParameters
1018 << ":EXT_blend_func_extended:" << mResources.EXT_blend_func_extended
1019 << ":EXT_frag_depth:" << mResources.EXT_frag_depth
1020 << ":EXT_shader_texture_lod:" << mResources.EXT_shader_texture_lod
1021 << ":EXT_shader_framebuffer_fetch:" << mResources.EXT_shader_framebuffer_fetch
1022 << ":NV_shader_framebuffer_fetch:" << mResources.NV_shader_framebuffer_fetch
1023 << ":ARM_shader_framebuffer_fetch:" << mResources.ARM_shader_framebuffer_fetch
1024 << ":OVR_multiview2:" << mResources.OVR_multiview2
1025 << ":OVR_multiview:" << mResources.OVR_multiview
1026 << ":EXT_YUV_target:" << mResources.EXT_YUV_target
1027 << ":EXT_geometry_shader:" << mResources.EXT_geometry_shader
1028 << ":OES_texture_3D:" << mResources.OES_texture_3D
1029 << ":MaxVertexOutputVectors:" << mResources.MaxVertexOutputVectors
1030 << ":MaxFragmentInputVectors:" << mResources.MaxFragmentInputVectors
1031 << ":MinProgramTexelOffset:" << mResources.MinProgramTexelOffset
1032 << ":MaxProgramTexelOffset:" << mResources.MaxProgramTexelOffset
1033 << ":MaxDualSourceDrawBuffers:" << mResources.MaxDualSourceDrawBuffers
1034 << ":MaxViewsOVR:" << mResources.MaxViewsOVR
1035 << ":NV_draw_buffers:" << mResources.NV_draw_buffers
1036 << ":WEBGL_debug_shader_precision:" << mResources.WEBGL_debug_shader_precision
1037 << ":ANGLE_multi_draw:" << mResources.ANGLE_multi_draw
1038 << ":ANGLE_base_vertex_base_instance:" << mResources.ANGLE_base_vertex_base_instance
1039 << ":MinProgramTextureGatherOffset:" << mResources.MinProgramTextureGatherOffset
1040 << ":MaxProgramTextureGatherOffset:" << mResources.MaxProgramTextureGatherOffset
1041 << ":MaxImageUnits:" << mResources.MaxImageUnits
1042 << ":MaxVertexImageUniforms:" << mResources.MaxVertexImageUniforms
1043 << ":MaxFragmentImageUniforms:" << mResources.MaxFragmentImageUniforms
1044 << ":MaxComputeImageUniforms:" << mResources.MaxComputeImageUniforms
1045 << ":MaxCombinedImageUniforms:" << mResources.MaxCombinedImageUniforms
1046 << ":MaxCombinedShaderOutputResources:" << mResources.MaxCombinedShaderOutputResources
1047 << ":MaxComputeWorkGroupCountX:" << mResources.MaxComputeWorkGroupCount[0]
1048 << ":MaxComputeWorkGroupCountY:" << mResources.MaxComputeWorkGroupCount[1]
1049 << ":MaxComputeWorkGroupCountZ:" << mResources.MaxComputeWorkGroupCount[2]
1050 << ":MaxComputeWorkGroupSizeX:" << mResources.MaxComputeWorkGroupSize[0]
1051 << ":MaxComputeWorkGroupSizeY:" << mResources.MaxComputeWorkGroupSize[1]
1052 << ":MaxComputeWorkGroupSizeZ:" << mResources.MaxComputeWorkGroupSize[2]
1053 << ":MaxComputeUniformComponents:" << mResources.MaxComputeUniformComponents
1054 << ":MaxComputeTextureImageUnits:" << mResources.MaxComputeTextureImageUnits
1055 << ":MaxComputeAtomicCounters:" << mResources.MaxComputeAtomicCounters
1056 << ":MaxComputeAtomicCounterBuffers:" << mResources.MaxComputeAtomicCounterBuffers
1057 << ":MaxVertexAtomicCounters:" << mResources.MaxVertexAtomicCounters
1058 << ":MaxFragmentAtomicCounters:" << mResources.MaxFragmentAtomicCounters
1059 << ":MaxCombinedAtomicCounters:" << mResources.MaxCombinedAtomicCounters
1060 << ":MaxAtomicCounterBindings:" << mResources.MaxAtomicCounterBindings
1061 << ":MaxVertexAtomicCounterBuffers:" << mResources.MaxVertexAtomicCounterBuffers
1062 << ":MaxFragmentAtomicCounterBuffers:" << mResources.MaxFragmentAtomicCounterBuffers
1063 << ":MaxCombinedAtomicCounterBuffers:" << mResources.MaxCombinedAtomicCounterBuffers
1064 << ":MaxAtomicCounterBufferSize:" << mResources.MaxAtomicCounterBufferSize
1065 << ":MaxGeometryUniformComponents:" << mResources.MaxGeometryUniformComponents
1066 << ":MaxGeometryUniformBlocks:" << mResources.MaxGeometryUniformBlocks
1067 << ":MaxGeometryInputComponents:" << mResources.MaxGeometryInputComponents
1068 << ":MaxGeometryOutputComponents:" << mResources.MaxGeometryOutputComponents
1069 << ":MaxGeometryOutputVertices:" << mResources.MaxGeometryOutputVertices
1070 << ":MaxGeometryTotalOutputComponents:" << mResources.MaxGeometryTotalOutputComponents
1071 << ":MaxGeometryTextureImageUnits:" << mResources.MaxGeometryTextureImageUnits
1072 << ":MaxGeometryAtomicCounterBuffers:" << mResources.MaxGeometryAtomicCounterBuffers
1073 << ":MaxGeometryAtomicCounters:" << mResources.MaxGeometryAtomicCounters
1074 << ":MaxGeometryShaderStorageBlocks:" << mResources.MaxGeometryShaderStorageBlocks
1075 << ":MaxGeometryShaderInvocations:" << mResources.MaxGeometryShaderInvocations
1076 << ":MaxGeometryImageUniforms:" << mResources.MaxGeometryImageUniforms;
1077 // clang-format on
1078
1079 mBuiltInResourcesString = strstream.str();
1080 }
1081
collectInterfaceBlocks()1082 void TCompiler::collectInterfaceBlocks()
1083 {
1084 ASSERT(mInterfaceBlocks.empty());
1085 mInterfaceBlocks.reserve(mUniformBlocks.size() + mShaderStorageBlocks.size() +
1086 mInBlocks.size());
1087 mInterfaceBlocks.insert(mInterfaceBlocks.end(), mUniformBlocks.begin(), mUniformBlocks.end());
1088 mInterfaceBlocks.insert(mInterfaceBlocks.end(), mShaderStorageBlocks.begin(),
1089 mShaderStorageBlocks.end());
1090 mInterfaceBlocks.insert(mInterfaceBlocks.end(), mInBlocks.begin(), mInBlocks.end());
1091 }
1092
clearResults()1093 void TCompiler::clearResults()
1094 {
1095 mArrayBoundsClamper.Cleanup();
1096 mInfoSink.info.erase();
1097 mInfoSink.obj.erase();
1098 mInfoSink.debug.erase();
1099 mDiagnostics.resetErrorCount();
1100
1101 mAttributes.clear();
1102 mOutputVariables.clear();
1103 mUniforms.clear();
1104 mInputVaryings.clear();
1105 mOutputVaryings.clear();
1106 mInterfaceBlocks.clear();
1107 mUniformBlocks.clear();
1108 mShaderStorageBlocks.clear();
1109 mInBlocks.clear();
1110 mVariablesCollected = false;
1111 mGLPositionInitialized = false;
1112
1113 mNumViews = -1;
1114
1115 mGeometryShaderInputPrimitiveType = EptUndefined;
1116 mGeometryShaderOutputPrimitiveType = EptUndefined;
1117 mGeometryShaderInvocations = 0;
1118 mGeometryShaderMaxVertices = -1;
1119
1120 mBuiltInFunctionEmulator.cleanup();
1121
1122 mNameMap.clear();
1123
1124 mSourcePath = nullptr;
1125
1126 mSymbolTable.clearCompilationResults();
1127 }
1128
initCallDag(TIntermNode * root)1129 bool TCompiler::initCallDag(TIntermNode *root)
1130 {
1131 mCallDag.clear();
1132
1133 switch (mCallDag.init(root, &mDiagnostics))
1134 {
1135 case CallDAG::INITDAG_SUCCESS:
1136 return true;
1137 case CallDAG::INITDAG_RECURSION:
1138 case CallDAG::INITDAG_UNDEFINED:
1139 // Error message has already been written out.
1140 ASSERT(mDiagnostics.numErrors() > 0);
1141 return false;
1142 }
1143
1144 UNREACHABLE();
1145 return true;
1146 }
1147
checkCallDepth()1148 bool TCompiler::checkCallDepth()
1149 {
1150 std::vector<int> depths(mCallDag.size());
1151
1152 for (size_t i = 0; i < mCallDag.size(); i++)
1153 {
1154 int depth = 0;
1155 const CallDAG::Record &record = mCallDag.getRecordFromIndex(i);
1156
1157 for (const int &calleeIndex : record.callees)
1158 {
1159 depth = std::max(depth, depths[calleeIndex] + 1);
1160 }
1161
1162 depths[i] = depth;
1163
1164 if (depth >= mResources.MaxCallStackDepth)
1165 {
1166 // Trace back the function chain to have a meaningful info log.
1167 std::stringstream errorStream = sh::InitializeStream<std::stringstream>();
1168 errorStream << "Call stack too deep (larger than " << mResources.MaxCallStackDepth
1169 << ") with the following call chain: "
1170 << record.node->getFunction()->name();
1171
1172 int currentFunction = static_cast<int>(i);
1173 int currentDepth = depth;
1174
1175 while (currentFunction != -1)
1176 {
1177 errorStream
1178 << " -> "
1179 << mCallDag.getRecordFromIndex(currentFunction).node->getFunction()->name();
1180
1181 int nextFunction = -1;
1182 for (const int &calleeIndex : mCallDag.getRecordFromIndex(currentFunction).callees)
1183 {
1184 if (depths[calleeIndex] == currentDepth - 1)
1185 {
1186 currentDepth--;
1187 nextFunction = calleeIndex;
1188 }
1189 }
1190
1191 currentFunction = nextFunction;
1192 }
1193
1194 std::string errorStr = errorStream.str();
1195 mDiagnostics.globalError(errorStr.c_str());
1196
1197 return false;
1198 }
1199 }
1200
1201 return true;
1202 }
1203
tagUsedFunctions()1204 bool TCompiler::tagUsedFunctions()
1205 {
1206 // Search from main, starting from the end of the DAG as it usually is the root.
1207 for (size_t i = mCallDag.size(); i-- > 0;)
1208 {
1209 if (mCallDag.getRecordFromIndex(i).node->getFunction()->isMain())
1210 {
1211 internalTagUsedFunction(i);
1212 return true;
1213 }
1214 }
1215
1216 mDiagnostics.globalError("Missing main()");
1217 return false;
1218 }
1219
internalTagUsedFunction(size_t index)1220 void TCompiler::internalTagUsedFunction(size_t index)
1221 {
1222 if (mFunctionMetadata[index].used)
1223 {
1224 return;
1225 }
1226
1227 mFunctionMetadata[index].used = true;
1228
1229 for (int calleeIndex : mCallDag.getRecordFromIndex(index).callees)
1230 {
1231 internalTagUsedFunction(calleeIndex);
1232 }
1233 }
1234
1235 // A predicate for the stl that returns if a top-level node is unused
1236 class TCompiler::UnusedPredicate
1237 {
1238 public:
UnusedPredicate(const CallDAG * callDag,const std::vector<FunctionMetadata> * metadatas)1239 UnusedPredicate(const CallDAG *callDag, const std::vector<FunctionMetadata> *metadatas)
1240 : mCallDag(callDag), mMetadatas(metadatas)
1241 {}
1242
operator ()(TIntermNode * node)1243 bool operator()(TIntermNode *node)
1244 {
1245 const TIntermFunctionPrototype *asFunctionPrototype = node->getAsFunctionPrototypeNode();
1246 const TIntermFunctionDefinition *asFunctionDefinition = node->getAsFunctionDefinition();
1247
1248 const TFunction *func = nullptr;
1249
1250 if (asFunctionDefinition)
1251 {
1252 func = asFunctionDefinition->getFunction();
1253 }
1254 else if (asFunctionPrototype)
1255 {
1256 func = asFunctionPrototype->getFunction();
1257 }
1258 if (func == nullptr)
1259 {
1260 return false;
1261 }
1262
1263 size_t callDagIndex = mCallDag->findIndex(func->uniqueId());
1264 if (callDagIndex == CallDAG::InvalidIndex)
1265 {
1266 // This happens only for unimplemented prototypes which are thus unused
1267 ASSERT(asFunctionPrototype);
1268 return true;
1269 }
1270
1271 ASSERT(callDagIndex < mMetadatas->size());
1272 return !(*mMetadatas)[callDagIndex].used;
1273 }
1274
1275 private:
1276 const CallDAG *mCallDag;
1277 const std::vector<FunctionMetadata> *mMetadatas;
1278 };
1279
pruneUnusedFunctions(TIntermBlock * root)1280 void TCompiler::pruneUnusedFunctions(TIntermBlock *root)
1281 {
1282 UnusedPredicate isUnused(&mCallDag, &mFunctionMetadata);
1283 TIntermSequence *sequence = root->getSequence();
1284
1285 if (!sequence->empty())
1286 {
1287 sequence->erase(std::remove_if(sequence->begin(), sequence->end(), isUnused),
1288 sequence->end());
1289 }
1290 }
1291
limitExpressionComplexity(TIntermBlock * root)1292 bool TCompiler::limitExpressionComplexity(TIntermBlock *root)
1293 {
1294 if (!IsASTDepthBelowLimit(root, mResources.MaxExpressionComplexity))
1295 {
1296 mDiagnostics.globalError("Expression too complex.");
1297 return false;
1298 }
1299
1300 if (!ValidateMaxParameters(root, mResources.MaxFunctionParameters))
1301 {
1302 mDiagnostics.globalError("Function has too many parameters.");
1303 return false;
1304 }
1305
1306 return true;
1307 }
1308
shouldCollectVariables(ShCompileOptions compileOptions)1309 bool TCompiler::shouldCollectVariables(ShCompileOptions compileOptions)
1310 {
1311 return (compileOptions & SH_VARIABLES) != 0;
1312 }
1313
wereVariablesCollected() const1314 bool TCompiler::wereVariablesCollected() const
1315 {
1316 return mVariablesCollected;
1317 }
1318
initializeGLPosition(TIntermBlock * root)1319 void TCompiler::initializeGLPosition(TIntermBlock *root)
1320 {
1321 InitVariableList list;
1322 sh::ShaderVariable var(GL_FLOAT_VEC4);
1323 var.name = "gl_Position";
1324 list.push_back(var);
1325 InitializeVariables(root, list, &mSymbolTable, mShaderVersion, mExtensionBehavior, false,
1326 false);
1327 }
1328
useAllMembersInUnusedStandardAndSharedBlocks(TIntermBlock * root)1329 void TCompiler::useAllMembersInUnusedStandardAndSharedBlocks(TIntermBlock *root)
1330 {
1331 sh::InterfaceBlockList list;
1332
1333 for (const sh::InterfaceBlock &block : mUniformBlocks)
1334 {
1335 if (!block.staticUse &&
1336 (block.layout == sh::BLOCKLAYOUT_STD140 || block.layout == sh::BLOCKLAYOUT_SHARED))
1337 {
1338 list.push_back(block);
1339 }
1340 }
1341
1342 sh::UseInterfaceBlockFields(root, list, mSymbolTable);
1343 }
1344
initializeOutputVariables(TIntermBlock * root)1345 void TCompiler::initializeOutputVariables(TIntermBlock *root)
1346 {
1347 InitVariableList list;
1348 if (mShaderType == GL_VERTEX_SHADER || mShaderType == GL_GEOMETRY_SHADER_EXT)
1349 {
1350 for (const sh::Varying &var : mOutputVaryings)
1351 {
1352 list.push_back(var);
1353 if (var.name == "gl_Position")
1354 {
1355 ASSERT(!mGLPositionInitialized);
1356 mGLPositionInitialized = true;
1357 }
1358 }
1359 }
1360 else
1361 {
1362 ASSERT(mShaderType == GL_FRAGMENT_SHADER);
1363 for (const sh::OutputVariable &var : mOutputVariables)
1364 {
1365 list.push_back(var);
1366 }
1367 }
1368 InitializeVariables(root, list, &mSymbolTable, mShaderVersion, mExtensionBehavior, false,
1369 false);
1370 }
1371
getExtensionBehavior() const1372 const TExtensionBehavior &TCompiler::getExtensionBehavior() const
1373 {
1374 return mExtensionBehavior;
1375 }
1376
getSourcePath() const1377 const char *TCompiler::getSourcePath() const
1378 {
1379 return mSourcePath;
1380 }
1381
getResources() const1382 const ShBuiltInResources &TCompiler::getResources() const
1383 {
1384 return mResources;
1385 }
1386
getArrayBoundsClamper() const1387 const ArrayBoundsClamper &TCompiler::getArrayBoundsClamper() const
1388 {
1389 return mArrayBoundsClamper;
1390 }
1391
getArrayIndexClampingStrategy() const1392 ShArrayIndexClampingStrategy TCompiler::getArrayIndexClampingStrategy() const
1393 {
1394 return mResources.ArrayIndexClampingStrategy;
1395 }
1396
getBuiltInFunctionEmulator() const1397 const BuiltInFunctionEmulator &TCompiler::getBuiltInFunctionEmulator() const
1398 {
1399 return mBuiltInFunctionEmulator;
1400 }
1401
writePragma(ShCompileOptions compileOptions)1402 void TCompiler::writePragma(ShCompileOptions compileOptions)
1403 {
1404 if (!(compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL))
1405 {
1406 TInfoSinkBase &sink = mInfoSink.obj;
1407 if (mPragma.stdgl.invariantAll)
1408 sink << "#pragma STDGL invariant(all)\n";
1409 }
1410 }
1411
isVaryingDefined(const char * varyingName)1412 bool TCompiler::isVaryingDefined(const char *varyingName)
1413 {
1414 ASSERT(mVariablesCollected);
1415 for (size_t ii = 0; ii < mInputVaryings.size(); ++ii)
1416 {
1417 if (mInputVaryings[ii].name == varyingName)
1418 {
1419 return true;
1420 }
1421 }
1422 for (size_t ii = 0; ii < mOutputVaryings.size(); ++ii)
1423 {
1424 if (mOutputVaryings[ii].name == varyingName)
1425 {
1426 return true;
1427 }
1428 }
1429
1430 return false;
1431 }
1432
EmitWorkGroupSizeGLSL(const TCompiler & compiler,TInfoSinkBase & sink)1433 void EmitWorkGroupSizeGLSL(const TCompiler &compiler, TInfoSinkBase &sink)
1434 {
1435 if (compiler.isComputeShaderLocalSizeDeclared())
1436 {
1437 const sh::WorkGroupSize &localSize = compiler.getComputeShaderLocalSize();
1438 sink << "layout (local_size_x=" << localSize[0] << ", local_size_y=" << localSize[1]
1439 << ", local_size_z=" << localSize[2] << ") in;\n";
1440 }
1441 }
1442
EmitMultiviewGLSL(const TCompiler & compiler,const ShCompileOptions & compileOptions,const TBehavior behavior,TInfoSinkBase & sink)1443 void EmitMultiviewGLSL(const TCompiler &compiler,
1444 const ShCompileOptions &compileOptions,
1445 const TBehavior behavior,
1446 TInfoSinkBase &sink)
1447 {
1448 ASSERT(behavior != EBhUndefined);
1449 if (behavior == EBhDisable)
1450 return;
1451
1452 const bool isVertexShader = (compiler.getShaderType() == GL_VERTEX_SHADER);
1453 if (compileOptions & SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW)
1454 {
1455 // Emit ARB_shader_viewport_layer_array/NV_viewport_array2 in a vertex shader if the
1456 // SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER option is set and the
1457 // OVR_multiview(2) extension is requested.
1458 if (isVertexShader && (compileOptions & SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER))
1459 {
1460 sink << "#if defined(GL_ARB_shader_viewport_layer_array)\n"
1461 << "#extension GL_ARB_shader_viewport_layer_array : require\n"
1462 << "#elif defined(GL_NV_viewport_array2)\n"
1463 << "#extension GL_NV_viewport_array2 : require\n"
1464 << "#endif\n";
1465 }
1466 }
1467 else
1468 {
1469 sink << "#extension GL_OVR_multiview2 : " << GetBehaviorString(behavior) << "\n";
1470
1471 const auto &numViews = compiler.getNumViews();
1472 if (isVertexShader && numViews != -1)
1473 {
1474 sink << "layout(num_views=" << numViews << ") in;\n";
1475 }
1476 }
1477 }
1478
1479 } // namespace sh
1480