summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src/compiler/translator/Compiler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/angle/src/compiler/translator/Compiler.cpp')
-rw-r--r--src/3rdparty/angle/src/compiler/translator/Compiler.cpp1111
1 files changed, 711 insertions, 400 deletions
diff --git a/src/3rdparty/angle/src/compiler/translator/Compiler.cpp b/src/3rdparty/angle/src/compiler/translator/Compiler.cpp
index 18524ce569..2f411cb58c 100644
--- a/src/3rdparty/angle/src/compiler/translator/Compiler.cpp
+++ b/src/3rdparty/angle/src/compiler/translator/Compiler.cpp
@@ -4,91 +4,193 @@
// found in the LICENSE file.
//
-#include "compiler/translator/Cache.h"
#include "compiler/translator/Compiler.h"
+
+#include <sstream>
+
+#include "angle_gl.h"
+#include "common/utilities.h"
+#include "compiler/translator/AddAndTrueToLoopCondition.h"
+#include "compiler/translator/Cache.h"
#include "compiler/translator/CallDAG.h"
-#include "compiler/translator/ForLoopUnroll.h"
+#include "compiler/translator/ClampPointSize.h"
+#include "compiler/translator/CollectVariables.h"
+#include "compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.h"
+#include "compiler/translator/DeferGlobalInitializers.h"
+#include "compiler/translator/EmulateGLFragColorBroadcast.h"
+#include "compiler/translator/EmulatePrecision.h"
#include "compiler/translator/Initialize.h"
-#include "compiler/translator/InitializeParseContext.h"
#include "compiler/translator/InitializeVariables.h"
+#include "compiler/translator/IntermNodePatternMatcher.h"
+#include "compiler/translator/IsASTDepthBelowLimit.h"
+#include "compiler/translator/OutputTree.h"
#include "compiler/translator/ParseContext.h"
-#include "compiler/translator/PruneEmptyDeclarations.h"
+#include "compiler/translator/PruneNoOps.h"
#include "compiler/translator/RegenerateStructNames.h"
+#include "compiler/translator/RemoveArrayLengthMethod.h"
+#include "compiler/translator/RemoveEmptySwitchStatements.h"
+#include "compiler/translator/RemoveInvariantDeclaration.h"
+#include "compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.h"
#include "compiler/translator/RemovePow.h"
-#include "compiler/translator/RenameFunction.h"
+#include "compiler/translator/RemoveUnreferencedVariables.h"
#include "compiler/translator/RewriteDoWhile.h"
#include "compiler/translator/ScalarizeVecAndMatConstructorArgs.h"
+#include "compiler/translator/SeparateDeclarations.h"
+#include "compiler/translator/SimplifyLoopConditions.h"
+#include "compiler/translator/SplitSequenceOperator.h"
#include "compiler/translator/UnfoldShortCircuitAST.h"
+#include "compiler/translator/UseInterfaceBlockFields.h"
#include "compiler/translator/ValidateLimitations.h"
+#include "compiler/translator/ValidateMaxParameters.h"
#include "compiler/translator/ValidateOutputs.h"
+#include "compiler/translator/ValidateVaryingLocations.h"
#include "compiler/translator/VariablePacker.h"
-#include "compiler/translator/depgraph/DependencyGraph.h"
-#include "compiler/translator/depgraph/DependencyGraphOutput.h"
-#include "compiler/translator/timing/RestrictFragmentShaderTiming.h"
-#include "compiler/translator/timing/RestrictVertexShaderTiming.h"
+#include "compiler/translator/VectorizeVectorScalarArithmetic.h"
+#include "compiler/translator/util.h"
#include "third_party/compiler/ArrayBoundsClamper.h"
-#include "angle_gl.h"
-#include "common/utilities.h"
+
+namespace sh
+{
+
+namespace
+{
+
+#if defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT)
+void DumpFuzzerCase(char const *const *shaderStrings,
+ size_t numStrings,
+ uint32_t type,
+ uint32_t spec,
+ uint32_t output,
+ uint64_t options)
+{
+ static int fileIndex = 0;
+
+ std::ostringstream o;
+ o << "corpus/" << fileIndex++ << ".sample";
+ std::string s = o.str();
+
+ // Must match the input format of the fuzzer
+ FILE *f = fopen(s.c_str(), "w");
+ fwrite(&type, sizeof(type), 1, f);
+ fwrite(&spec, sizeof(spec), 1, f);
+ fwrite(&output, sizeof(output), 1, f);
+ fwrite(&options, sizeof(options), 1, f);
+
+ char zero[128 - 20] = {0};
+ fwrite(&zero, 128 - 20, 1, f);
+
+ for (size_t i = 0; i < numStrings; i++)
+ {
+ fwrite(shaderStrings[i], sizeof(char), strlen(shaderStrings[i]), f);
+ }
+ fwrite(&zero, 1, 1, f);
+
+ fclose(f);
+}
+#endif // defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT)
+} // anonymous namespace
bool IsWebGLBasedSpec(ShShaderSpec spec)
{
- return (spec == SH_WEBGL_SPEC ||
- spec == SH_CSS_SHADERS_SPEC ||
- spec == SH_WEBGL2_SPEC);
+ return (spec == SH_WEBGL_SPEC || spec == SH_WEBGL2_SPEC || spec == SH_WEBGL3_SPEC);
}
bool IsGLSL130OrNewer(ShShaderOutput output)
{
- return (output == SH_GLSL_130_OUTPUT ||
- output == SH_GLSL_140_OUTPUT ||
- output == SH_GLSL_150_CORE_OUTPUT ||
- output == SH_GLSL_330_CORE_OUTPUT ||
- output == SH_GLSL_400_CORE_OUTPUT ||
- output == SH_GLSL_410_CORE_OUTPUT ||
- output == SH_GLSL_420_CORE_OUTPUT ||
- output == SH_GLSL_430_CORE_OUTPUT ||
- output == SH_GLSL_440_CORE_OUTPUT ||
- output == SH_GLSL_450_CORE_OUTPUT);
+ return (output == SH_GLSL_130_OUTPUT || output == SH_GLSL_140_OUTPUT ||
+ output == SH_GLSL_150_CORE_OUTPUT || output == SH_GLSL_330_CORE_OUTPUT ||
+ output == SH_GLSL_400_CORE_OUTPUT || output == SH_GLSL_410_CORE_OUTPUT ||
+ output == SH_GLSL_420_CORE_OUTPUT || output == SH_GLSL_430_CORE_OUTPUT ||
+ output == SH_GLSL_440_CORE_OUTPUT || output == SH_GLSL_450_CORE_OUTPUT);
+}
+
+bool IsGLSL420OrNewer(ShShaderOutput output)
+{
+ return (output == SH_GLSL_420_CORE_OUTPUT || output == SH_GLSL_430_CORE_OUTPUT ||
+ output == SH_GLSL_440_CORE_OUTPUT || output == SH_GLSL_450_CORE_OUTPUT);
+}
+
+bool IsGLSL410OrOlder(ShShaderOutput output)
+{
+ return (output == SH_GLSL_130_OUTPUT || output == SH_GLSL_140_OUTPUT ||
+ output == SH_GLSL_150_CORE_OUTPUT || output == SH_GLSL_330_CORE_OUTPUT ||
+ output == SH_GLSL_400_CORE_OUTPUT || output == SH_GLSL_410_CORE_OUTPUT);
+}
+
+bool RemoveInvariant(sh::GLenum shaderType,
+ int shaderVersion,
+ ShShaderOutput outputType,
+ ShCompileOptions compileOptions)
+{
+ if ((compileOptions & SH_DONT_REMOVE_INVARIANT_FOR_FRAGMENT_INPUT) == 0 &&
+ shaderType == GL_FRAGMENT_SHADER && IsGLSL420OrNewer(outputType))
+ return true;
+
+ if ((compileOptions & SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3) != 0 &&
+ shaderVersion >= 300 && shaderType == GL_VERTEX_SHADER)
+ return true;
+
+ return false;
}
size_t GetGlobalMaxTokenSize(ShShaderSpec spec)
{
- // WebGL defines a max token legnth of 256, while ES2 leaves max token
+ // WebGL defines a max token length of 256, while ES2 leaves max token
// size undefined. ES3 defines a max size of 1024 characters.
switch (spec)
{
- case SH_WEBGL_SPEC:
- case SH_CSS_SHADERS_SPEC:
- return 256;
- default:
- return 1024;
+ case SH_WEBGL_SPEC:
+ return 256;
+ default:
+ return 1024;
}
}
-namespace {
+int GetMaxUniformVectorsForShaderType(GLenum shaderType, const ShBuiltInResources &resources)
+{
+ switch (shaderType)
+ {
+ case GL_VERTEX_SHADER:
+ return resources.MaxVertexUniformVectors;
+ case GL_FRAGMENT_SHADER:
+ return resources.MaxFragmentUniformVectors;
+
+ // TODO (jiawei.shao@intel.com): check if we need finer-grained component counting
+ case GL_COMPUTE_SHADER:
+ return resources.MaxComputeUniformComponents / 4;
+ case GL_GEOMETRY_SHADER_OES:
+ return resources.MaxGeometryUniformComponents / 4;
+ default:
+ UNREACHABLE();
+ return -1;
+ }
+}
+
+namespace
+{
class TScopedPoolAllocator
{
public:
- TScopedPoolAllocator(TPoolAllocator* allocator) : mAllocator(allocator)
+ TScopedPoolAllocator(TPoolAllocator *allocator) : mAllocator(allocator)
{
mAllocator->push();
SetGlobalPoolAllocator(mAllocator);
}
~TScopedPoolAllocator()
{
- SetGlobalPoolAllocator(NULL);
+ SetGlobalPoolAllocator(nullptr);
mAllocator->pop();
}
private:
- TPoolAllocator* mAllocator;
+ TPoolAllocator *mAllocator;
};
class TScopedSymbolTableLevel
{
public:
- TScopedSymbolTableLevel(TSymbolTable* table) : mTable(table)
+ TScopedSymbolTableLevel(TSymbolTable *table) : mTable(table)
{
ASSERT(mTable->atBuiltInLevel());
mTable->push();
@@ -100,23 +202,25 @@ class TScopedSymbolTableLevel
}
private:
- TSymbolTable* mTable;
+ TSymbolTable *mTable;
};
int MapSpecToShaderVersion(ShShaderSpec spec)
{
switch (spec)
{
- case SH_GLES2_SPEC:
- case SH_WEBGL_SPEC:
- case SH_CSS_SHADERS_SPEC:
- return 100;
- case SH_GLES3_SPEC:
- case SH_WEBGL2_SPEC:
- return 300;
- default:
- UNREACHABLE();
- return 0;
+ case SH_GLES2_SPEC:
+ case SH_WEBGL_SPEC:
+ return 100;
+ case SH_GLES3_SPEC:
+ case SH_WEBGL2_SPEC:
+ return 300;
+ case SH_GLES3_1_SPEC:
+ case SH_WEBGL3_SPEC:
+ return 310;
+ default:
+ UNREACHABLE();
+ return 0;
}
}
@@ -130,22 +234,31 @@ TShHandleBase::TShHandleBase()
TShHandleBase::~TShHandleBase()
{
- SetGlobalPoolAllocator(NULL);
+ SetGlobalPoolAllocator(nullptr);
allocator.popAll();
}
TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
- : shaderType(type),
+ : variablesCollected(false),
+ mGLPositionInitialized(false),
+ shaderType(type),
shaderSpec(spec),
outputType(output),
maxUniformVectors(0),
maxExpressionComplexity(0),
maxCallStackDepth(0),
+ maxFunctionParameters(0),
fragmentPrecisionHigh(false),
clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC),
builtInFunctionEmulator(),
- mSourcePath(NULL),
- mTemporaryIndex(0)
+ mDiagnostics(infoSink.info),
+ mSourcePath(nullptr),
+ mComputeShaderLocalSizeDeclared(false),
+ mComputeShaderLocalSize(1),
+ mGeometryShaderMaxVertices(-1),
+ mGeometryShaderInvocations(0),
+ mGeometryShaderInputPrimitiveType(EptUndefined),
+ mGeometryShaderOutputPrimitiveType(EptUndefined)
{
}
@@ -153,7 +266,7 @@ TCompiler::~TCompiler()
{
}
-bool TCompiler::shouldRunLoopAndIndexingValidation(int compileOptions) const
+bool TCompiler::shouldRunLoopAndIndexingValidation(ShCompileOptions compileOptions) const
{
// If compiling an ESSL 1.00 shader for WebGL, or if its been requested through the API,
// validate loop and indexing as well (to verify that the shader only uses minimal functionality
@@ -162,14 +275,15 @@ bool TCompiler::shouldRunLoopAndIndexingValidation(int compileOptions) const
(compileOptions & SH_VALIDATE_LOOP_INDEXING);
}
-bool TCompiler::Init(const ShBuiltInResources& resources)
+bool TCompiler::Init(const ShBuiltInResources &resources)
{
shaderVersion = 100;
- maxUniformVectors = (shaderType == GL_VERTEX_SHADER) ?
- resources.MaxVertexUniformVectors :
- resources.MaxFragmentUniformVectors;
+
+ maxUniformVectors = GetMaxUniformVectorsForShaderType(shaderType, resources);
+
maxExpressionComplexity = resources.MaxExpressionComplexity;
- maxCallStackDepth = resources.MaxCallStackDepth;
+ maxCallStackDepth = resources.MaxCallStackDepth;
+ maxFunctionParameters = resources.MaxFunctionParameters;
SetGlobalPoolAllocator(&allocator);
@@ -187,15 +301,16 @@ bool TCompiler::Init(const ShBuiltInResources& resources)
return true;
}
-TIntermNode *TCompiler::compileTreeForTesting(const char* const shaderStrings[],
- size_t numStrings, int compileOptions)
+TIntermBlock *TCompiler::compileTreeForTesting(const char *const shaderStrings[],
+ size_t numStrings,
+ ShCompileOptions compileOptions)
{
return compileTreeImpl(shaderStrings, numStrings, compileOptions);
}
-TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[],
- size_t numStrings,
- const int compileOptions)
+TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
+ size_t numStrings,
+ const ShCompileOptions compileOptions)
{
clearResults();
@@ -213,191 +328,347 @@ TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[],
++firstSource;
}
- TIntermediate intermediate(infoSink);
- TParseContext parseContext(symbolTable, extensionBehavior, intermediate, shaderType, shaderSpec,
- compileOptions, true, infoSink, getResources());
+ TParseContext parseContext(symbolTable, extensionBehavior, shaderType, shaderSpec,
+ compileOptions, true, &mDiagnostics, getResources());
parseContext.setFragmentPrecisionHighOnESSL1(fragmentPrecisionHigh);
- SetGlobalParseContext(&parseContext);
// We preserve symbols at the built-in level from compile-to-compile.
// Start pushing the user-defined symbols at global level.
TScopedSymbolTableLevel scopedSymbolLevel(&symbolTable);
// Parse shader.
- bool success =
- (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], nullptr, &parseContext) == 0) &&
- (parseContext.getTreeRoot() != nullptr);
+ if (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], nullptr,
+ &parseContext) != 0)
+ {
+ return nullptr;
+ }
+
+ if (parseContext.getTreeRoot() == nullptr)
+ {
+ return nullptr;
+ }
+
+ setASTMetadata(parseContext);
+
+ if (MapSpecToShaderVersion(shaderSpec) < shaderVersion)
+ {
+ mDiagnostics.globalError("unsupported shader version");
+ return nullptr;
+ }
+ TIntermBlock *root = parseContext.getTreeRoot();
+ if (!checkAndSimplifyAST(root, parseContext, compileOptions))
+ {
+ return nullptr;
+ }
+
+ return root;
+}
+
+void TCompiler::setASTMetadata(const TParseContext &parseContext)
+{
shaderVersion = parseContext.getShaderVersion();
- if (success && MapSpecToShaderVersion(shaderSpec) < shaderVersion)
+
+ mPragma = parseContext.pragma();
+ symbolTable.setGlobalInvariant(mPragma.stdgl.invariantAll);
+
+ mComputeShaderLocalSizeDeclared = parseContext.isComputeShaderLocalSizeDeclared();
+ mComputeShaderLocalSize = parseContext.getComputeShaderLocalSize();
+
+ mNumViews = parseContext.getNumViews();
+
+ // Highp might have been auto-enabled based on shader version
+ fragmentPrecisionHigh = parseContext.getFragmentPrecisionHigh();
+
+ if (shaderType == GL_GEOMETRY_SHADER_OES)
{
- infoSink.info.prefix(EPrefixError);
- infoSink.info << "unsupported shader version";
- success = false;
+ mGeometryShaderInputPrimitiveType = parseContext.getGeometryShaderInputPrimitiveType();
+ mGeometryShaderOutputPrimitiveType = parseContext.getGeometryShaderOutputPrimitiveType();
+ mGeometryShaderMaxVertices = parseContext.getGeometryShaderMaxVertices();
+ mGeometryShaderInvocations = parseContext.getGeometryShaderInvocations();
}
+}
- TIntermNode *root = nullptr;
+bool TCompiler::checkAndSimplifyAST(TIntermBlock *root,
+ const TParseContext &parseContext,
+ ShCompileOptions compileOptions)
+{
+ // Disallow expressions deemed too complex.
+ if ((compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY) && !limitExpressionComplexity(root))
+ {
+ return false;
+ }
- if (success)
+ // We prune no-ops to work around driver bugs and to keep AST processing and output simple.
+ // The following kinds of no-ops are pruned:
+ // 1. Empty declarations "int;".
+ // 2. Literal statements: "1.0;". The ESSL output doesn't define a default precision
+ // for float, so float literal statements would end up with no precision which is
+ // invalid ESSL.
+ // After this empty declarations are not allowed in the AST.
+ PruneNoOps(root);
+
+ // In case the last case inside a switch statement is a certain type of no-op, GLSL
+ // compilers in drivers may not accept it. In this case we clean up the dead code from the
+ // end of switch statements. This is also required because PruneNoOps may have left switch
+ // statements that only contained an empty declaration inside the final case in an invalid
+ // state. Relies on that PruneNoOps has already been run.
+ RemoveNoOpCasesFromEndOfSwitchStatements(root, &symbolTable);
+
+ // Remove empty switch statements - this makes output simpler.
+ RemoveEmptySwitchStatements(root);
+
+ // Create the function DAG and check there is no recursion
+ if (!initCallDag(root))
{
- mPragma = parseContext.pragma();
- if (mPragma.stdgl.invariantAll)
- {
- symbolTable.setGlobalInvariant();
- }
+ return false;
+ }
- root = parseContext.getTreeRoot();
- root = intermediate.postProcess(root);
+ if ((compileOptions & SH_LIMIT_CALL_STACK_DEPTH) && !checkCallDepth())
+ {
+ return false;
+ }
- // Highp might have been auto-enabled based on shader version
- fragmentPrecisionHigh = parseContext.getFragmentPrecisionHigh();
+ // Checks which functions are used and if "main" exists
+ functionMetadata.clear();
+ functionMetadata.resize(mCallDag.size());
+ if (!tagUsedFunctions())
+ {
+ return false;
+ }
- // Disallow expressions deemed too complex.
- if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY))
- success = limitExpressionComplexity(root);
+ if (!(compileOptions & SH_DONT_PRUNE_UNUSED_FUNCTIONS))
+ {
+ pruneUnusedFunctions(root);
+ }
- // Create the function DAG and check there is no recursion
- if (success)
- success = initCallDag(root);
+ if (shaderVersion >= 310 && !ValidateVaryingLocations(root, &mDiagnostics, shaderType))
+ {
+ return false;
+ }
- if (success && (compileOptions & SH_LIMIT_CALL_STACK_DEPTH))
- success = checkCallDepth();
+ if (shaderVersion >= 300 && shaderType == GL_FRAGMENT_SHADER &&
+ !ValidateOutputs(root, getExtensionBehavior(), compileResources.MaxDrawBuffers,
+ &mDiagnostics))
+ {
+ return false;
+ }
- // Checks which functions are used and if "main" exists
- if (success)
- {
- functionMetadata.clear();
- functionMetadata.resize(mCallDag.size());
- success = tagUsedFunctions();
- }
+ if (shouldRunLoopAndIndexingValidation(compileOptions) &&
+ !ValidateLimitations(root, shaderType, &symbolTable, shaderVersion, &mDiagnostics))
+ {
+ return false;
+ }
- if (success && !(compileOptions & SH_DONT_PRUNE_UNUSED_FUNCTIONS))
- success = pruneUnusedFunctions(root);
+ // Fail compilation if precision emulation not supported.
+ if (getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision &&
+ !EmulatePrecision::SupportedInLanguage(outputType))
+ {
+ mDiagnostics.globalError("Precision emulation not supported for this output type.");
+ return false;
+ }
- // Prune empty declarations to work around driver bugs and to keep declaration output simple.
- if (success)
- PruneEmptyDeclarations(root);
+ // Clamping uniform array bounds needs to happen after validateLimitations pass.
+ if (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS)
+ {
+ arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root);
+ }
- if (success && shaderVersion == 300 && shaderType == GL_FRAGMENT_SHADER)
- success = validateOutputs(root);
+ if ((compileOptions & SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW) &&
+ parseContext.isExtensionEnabled(TExtension::OVR_multiview) &&
+ getShaderType() != GL_COMPUTE_SHADER)
+ {
+ DeclareAndInitBuiltinsForInstancedMultiview(root, mNumViews, shaderType, compileOptions,
+ outputType, &symbolTable);
+ }
- if (success && shouldRunLoopAndIndexingValidation(compileOptions))
- success = validateLimitations(root);
+ // This pass might emit short circuits so keep it before the short circuit unfolding
+ if (compileOptions & SH_REWRITE_DO_WHILE_LOOPS)
+ RewriteDoWhile(root, &symbolTable);
- if (success && (compileOptions & SH_TIMING_RESTRICTIONS))
- success = enforceTimingRestrictions(root, (compileOptions & SH_DEPENDENCY_GRAPH) != 0);
+ if (compileOptions & SH_ADD_AND_TRUE_TO_LOOP_CONDITION)
+ sh::AddAndTrueToLoopCondition(root);
- if (success && shaderSpec == SH_CSS_SHADERS_SPEC)
- rewriteCSSShader(root);
+ if (compileOptions & SH_UNFOLD_SHORT_CIRCUIT)
+ {
+ UnfoldShortCircuitAST unfoldShortCircuit;
+ root->traverse(&unfoldShortCircuit);
+ unfoldShortCircuit.updateTree();
+ }
- // Unroll for-loop markup needs to happen after validateLimitations pass.
- if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX))
- {
- ForLoopUnrollMarker marker(ForLoopUnrollMarker::kIntegerIndex,
- shouldRunLoopAndIndexingValidation(compileOptions));
- root->traverse(&marker);
- }
- if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX))
- {
- ForLoopUnrollMarker marker(ForLoopUnrollMarker::kSamplerArrayIndex,
- shouldRunLoopAndIndexingValidation(compileOptions));
- root->traverse(&marker);
- if (marker.samplerArrayIndexIsFloatLoopIndex())
- {
- infoSink.info.prefix(EPrefixError);
- infoSink.info << "sampler array index is float loop index";
- success = false;
- }
- }
+ if (compileOptions & SH_REMOVE_POW_WITH_CONSTANT_EXPONENT)
+ {
+ RemovePow(root);
+ }
- // Built-in function emulation needs to happen after validateLimitations pass.
- if (success)
- {
- initBuiltInFunctionEmulator(&builtInFunctionEmulator, compileOptions);
- builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root);
- }
+ if (compileOptions & SH_REGENERATE_STRUCT_NAMES)
+ {
+ RegenerateStructNames gen(&symbolTable, shaderVersion);
+ root->traverse(&gen);
+ }
- // Clamping uniform array bounds needs to happen after validateLimitations pass.
- if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS))
- arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root);
+ if (shaderType == GL_FRAGMENT_SHADER && shaderVersion == 100 &&
+ compileResources.EXT_draw_buffers && compileResources.MaxDrawBuffers > 1 &&
+ IsExtensionEnabled(extensionBehavior, TExtension::EXT_draw_buffers))
+ {
+ EmulateGLFragColorBroadcast(root, compileResources.MaxDrawBuffers, &outputVariables,
+ &symbolTable, shaderVersion);
+ }
- // gl_Position is always written in compatibility output mode
- if (success && shaderType == GL_VERTEX_SHADER &&
- ((compileOptions & SH_INIT_GL_POSITION) ||
- (outputType == SH_GLSL_COMPATIBILITY_OUTPUT)))
- initializeGLPosition(root);
+ // Split multi declarations and remove calls to array length().
+ // Note that SimplifyLoopConditions needs to be run before any other AST transformations
+ // that may need to generate new statements from loop conditions or loop expressions.
+ SimplifyLoopConditions(
+ root,
+ IntermNodePatternMatcher::kMultiDeclaration | IntermNodePatternMatcher::kArrayLengthMethod,
+ &getSymbolTable(), getShaderVersion());
- // This pass might emit short circuits so keep it before the short circuit unfolding
- if (success && (compileOptions & SH_REWRITE_DO_WHILE_LOOPS))
- RewriteDoWhile(root, getTemporaryIndex());
+ // Note that separate declarations need to be run before other AST transformations that
+ // generate new statements from expressions.
+ SeparateDeclarations(root);
- if (success && (compileOptions & SH_UNFOLD_SHORT_CIRCUIT))
- {
- UnfoldShortCircuitAST unfoldShortCircuit;
- root->traverse(&unfoldShortCircuit);
- unfoldShortCircuit.updateTree();
- }
+ SplitSequenceOperator(root, IntermNodePatternMatcher::kArrayLengthMethod, &getSymbolTable(),
+ getShaderVersion());
+
+ RemoveArrayLengthMethod(root);
+
+ RemoveUnreferencedVariables(root, &symbolTable);
- if (success && (compileOptions & SH_REMOVE_POW_WITH_CONSTANT_EXPONENT))
+ // Built-in function emulation needs to happen after validateLimitations pass.
+ // TODO(jmadill): Remove global pool allocator.
+ GetGlobalPoolAllocator()->lock();
+ initBuiltInFunctionEmulator(&builtInFunctionEmulator, compileOptions);
+ GetGlobalPoolAllocator()->unlock();
+ builtInFunctionEmulator.markBuiltInFunctionsForEmulation(root);
+
+ if (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS)
+ {
+ ScalarizeVecAndMatConstructorArgs(root, shaderType, fragmentPrecisionHigh, &symbolTable);
+ }
+
+ if (shouldCollectVariables(compileOptions))
+ {
+ ASSERT(!variablesCollected);
+ CollectVariables(root, &attributes, &outputVariables, &uniforms, &inputVaryings,
+ &outputVaryings, &uniformBlocks, &shaderStorageBlocks, &inBlocks,
+ hashFunction, &symbolTable, shaderVersion, shaderType, extensionBehavior);
+ collectInterfaceBlocks();
+ variablesCollected = true;
+ if (compileOptions & SH_USE_UNUSED_STANDARD_SHARED_BLOCKS)
{
- RemovePow(root);
+ useAllMembersInUnusedStandardAndSharedBlocks(root);
}
-
- if (success && shouldCollectVariables(compileOptions))
+ if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS)
{
- collectVariables(root);
- if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS)
+ // Returns true if, after applying the packing rules in the GLSL ES 1.00.17 spec
+ // Appendix A, section 7, the shader does not use too many uniforms.
+ if (!CheckVariablesInPackingLimits(maxUniformVectors, uniforms))
{
- success = enforcePackingRestrictions();
- if (!success)
- {
- infoSink.info.prefix(EPrefixError);
- infoSink.info << "too many uniforms";
- }
+ mDiagnostics.globalError("too many uniforms");
+ return false;
}
- if (success && shaderType == GL_VERTEX_SHADER &&
- (compileOptions & SH_INIT_VARYINGS_WITHOUT_STATIC_USE))
- initializeVaryingsWithoutStaticUse(root);
}
-
- if (success && (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS))
+ if (compileOptions & SH_INIT_OUTPUT_VARIABLES)
{
- ScalarizeVecAndMatConstructorArgs scalarizer(
- shaderType, fragmentPrecisionHigh);
- root->traverse(&scalarizer);
+ initializeOutputVariables(root);
}
+ }
+
+ // Removing invariant declarations must be done after collecting variables.
+ // Otherwise, built-in invariant declarations don't apply.
+ if (RemoveInvariant(shaderType, shaderVersion, outputType, compileOptions))
+ {
+ RemoveInvariantDeclaration(root);
+ }
+
+ // gl_Position is always written in compatibility output mode.
+ // It may have been already initialized among other output variables, in that case we don't
+ // need to initialize it twice.
+ if (shaderType == GL_VERTEX_SHADER && !mGLPositionInitialized &&
+ ((compileOptions & SH_INIT_GL_POSITION) || (outputType == SH_GLSL_COMPATIBILITY_OUTPUT)))
+ {
+ initializeGLPosition(root);
+ mGLPositionInitialized = true;
+ }
+
+ // DeferGlobalInitializers needs to be run before other AST transformations that generate new
+ // statements from expressions. But it's fine to run DeferGlobalInitializers after the above
+ // SplitSequenceOperator and RemoveArrayLengthMethod since they only have an effect on the AST
+ // on ESSL >= 3.00, and the initializers that need to be deferred can only exist in ESSL < 3.00.
+ bool initializeLocalsAndGlobals =
+ (compileOptions & SH_INITIALIZE_UNINITIALIZED_LOCALS) && !IsOutputHLSL(getOutputType());
+ bool canUseLoopsToInitialize = !(compileOptions & SH_DONT_USE_LOOPS_TO_INITIALIZE_VARIABLES);
+ DeferGlobalInitializers(root, initializeLocalsAndGlobals, canUseLoopsToInitialize, &symbolTable);
- if (success && (compileOptions & SH_REGENERATE_STRUCT_NAMES))
+ if (initializeLocalsAndGlobals)
+ {
+ // Initialize uninitialized local variables.
+ // In some cases initializing can generate extra statements in the parent block, such as
+ // when initializing nameless structs or initializing arrays in ESSL 1.00. In that case
+ // we need to first simplify loop conditions. We've already separated declarations
+ // earlier, which is also required. If we don't follow the Appendix A limitations, loop
+ // init statements can declare arrays or nameless structs and have multiple
+ // declarations.
+
+ if (!shouldRunLoopAndIndexingValidation(compileOptions))
{
- RegenerateStructNames gen(symbolTable, shaderVersion);
- root->traverse(&gen);
+ SimplifyLoopConditions(root,
+ IntermNodePatternMatcher::kArrayDeclaration |
+ IntermNodePatternMatcher::kNamelessStructDeclaration,
+ &getSymbolTable(), getShaderVersion());
}
+
+ InitializeUninitializedLocals(root, getShaderVersion(), canUseLoopsToInitialize,
+ &getSymbolTable());
}
- SetGlobalParseContext(NULL);
- if (success)
- return root;
+ if (getShaderType() == GL_VERTEX_SHADER && (compileOptions & SH_CLAMP_POINT_SIZE))
+ {
+ ClampPointSize(root, compileResources.MaxPointSize, &getSymbolTable());
+ }
- return NULL;
+ if (compileOptions & SH_REWRITE_VECTOR_SCALAR_ARITHMETIC)
+ {
+ VectorizeVectorScalarArithmetic(root, &getSymbolTable());
+ }
+
+ return true;
}
-bool TCompiler::compile(const char* const shaderStrings[],
- size_t numStrings, int compileOptions)
+bool TCompiler::compile(const char *const shaderStrings[],
+ size_t numStrings,
+ ShCompileOptions compileOptionsIn)
{
+#if defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT)
+ DumpFuzzerCase(shaderStrings, numStrings, shaderType, shaderSpec, outputType, compileOptionsIn);
+#endif // defined(ANGLE_ENABLE_FUZZER_CORPUS_OUTPUT)
+
if (numStrings == 0)
return true;
+ ShCompileOptions compileOptions = compileOptionsIn;
+
+ // Apply key workarounds.
+ if (shouldFlattenPragmaStdglInvariantAll())
+ {
+ // This should be harmless to do in all cases, but for the moment, do it only conditionally.
+ compileOptions |= SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL;
+ }
+
TScopedPoolAllocator scopedAlloc(&allocator);
- TIntermNode *root = compileTreeImpl(shaderStrings, numStrings, compileOptions);
+ TIntermBlock *root = compileTreeImpl(shaderStrings, numStrings, compileOptions);
if (root)
{
if (compileOptions & SH_INTERMEDIATE_TREE)
- TIntermediate::outputTree(root, infoSink.info);
+ OutputTree(root, infoSink.info);
if (compileOptions & SH_OBJECT_CODE)
- translate(root, compileOptions);
+ {
+ PerformanceDiagnostics perfDiagnostics(&mDiagnostics);
+ translate(root, compileOptions, &perfDiagnostics);
+ }
// The IntermNode tree doesn't need to be deleted here, since the
// memory will be freed in a big chunk by the PoolAllocator.
@@ -408,37 +679,38 @@ bool TCompiler::compile(const char* const shaderStrings[],
bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
{
+ if (resources.MaxDrawBuffers < 1)
+ {
+ return false;
+ }
+ if (resources.EXT_blend_func_extended && resources.MaxDualSourceDrawBuffers < 1)
+ {
+ return false;
+ }
+
compileResources = resources;
setResourceString();
- assert(symbolTable.isEmpty());
- symbolTable.push(); // COMMON_BUILTINS
- symbolTable.push(); // ESSL1_BUILTINS
- symbolTable.push(); // ESSL3_BUILTINS
-
- TPublicType integer;
- integer.type = EbtInt;
- integer.primarySize = 1;
- integer.secondarySize = 1;
- integer.array = false;
-
- TPublicType floatingPoint;
- floatingPoint.type = EbtFloat;
- floatingPoint.primarySize = 1;
- floatingPoint.secondarySize = 1;
- floatingPoint.array = false;
-
- switch(shaderType)
- {
- case GL_FRAGMENT_SHADER:
- symbolTable.setDefaultPrecision(integer, EbpMedium);
- break;
- case GL_VERTEX_SHADER:
- symbolTable.setDefaultPrecision(integer, EbpHigh);
- symbolTable.setDefaultPrecision(floatingPoint, EbpHigh);
- break;
- default:
- assert(false && "Language not supported");
+ ASSERT(symbolTable.isEmpty());
+ symbolTable.push(); // COMMON_BUILTINS
+ symbolTable.push(); // ESSL1_BUILTINS
+ symbolTable.push(); // ESSL3_BUILTINS
+ symbolTable.push(); // ESSL3_1_BUILTINS
+ symbolTable.push(); // GLSL_BUILTINS
+
+ switch (shaderType)
+ {
+ case GL_FRAGMENT_SHADER:
+ symbolTable.setDefaultPrecision(EbtInt, EbpMedium);
+ break;
+ case GL_VERTEX_SHADER:
+ case GL_COMPUTE_SHADER:
+ case GL_GEOMETRY_SHADER_OES:
+ symbolTable.setDefaultPrecision(EbtInt, EbpHigh);
+ symbolTable.setDefaultPrecision(EbtFloat, EbpHigh);
+ break;
+ default:
+ UNREACHABLE();
}
// Set defaults for sampler types that have default precision, even those that are
// only available if an extension exists.
@@ -447,9 +719,13 @@ bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
initSamplerDefaultPrecision(EbtSamplerCube);
// SamplerExternalOES is specified in the extension to have default precision.
initSamplerDefaultPrecision(EbtSamplerExternalOES);
+ // SamplerExternal2DY2YEXT is specified in the extension to have default precision.
+ initSamplerDefaultPrecision(EbtSamplerExternal2DY2YEXT);
// It isn't specified whether Sampler2DRect has default precision.
initSamplerDefaultPrecision(EbtSampler2DRect);
+ symbolTable.setDefaultPrecision(EbtAtomicCounter, EbpHigh);
+
InsertBuiltInFunctions(shaderType, shaderSpec, resources, symbolTable);
IdentifyBuiltIns(shaderType, shaderSpec, resources, symbolTable);
@@ -460,87 +736,149 @@ bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
void TCompiler::initSamplerDefaultPrecision(TBasicType samplerType)
{
ASSERT(samplerType > EbtGuardSamplerBegin && samplerType < EbtGuardSamplerEnd);
- TPublicType sampler;
- sampler.primarySize = 1;
- sampler.secondarySize = 1;
- sampler.array = false;
- sampler.type = samplerType;
- symbolTable.setDefaultPrecision(sampler, EbpLow);
+ symbolTable.setDefaultPrecision(samplerType, EbpLow);
}
void TCompiler::setResourceString()
{
std::ostringstream strstream;
+
+ // clang-format off
strstream << ":MaxVertexAttribs:" << compileResources.MaxVertexAttribs
- << ":MaxVertexUniformVectors:" << compileResources.MaxVertexUniformVectors
- << ":MaxVaryingVectors:" << compileResources.MaxVaryingVectors
- << ":MaxVertexTextureImageUnits:" << compileResources.MaxVertexTextureImageUnits
- << ":MaxCombinedTextureImageUnits:" << compileResources.MaxCombinedTextureImageUnits
- << ":MaxTextureImageUnits:" << compileResources.MaxTextureImageUnits
- << ":MaxFragmentUniformVectors:" << compileResources.MaxFragmentUniformVectors
- << ":MaxDrawBuffers:" << compileResources.MaxDrawBuffers
- << ":OES_standard_derivatives:" << compileResources.OES_standard_derivatives
- << ":OES_EGL_image_external:" << compileResources.OES_EGL_image_external
- << ":ARB_texture_rectangle:" << compileResources.ARB_texture_rectangle
- << ":EXT_draw_buffers:" << compileResources.EXT_draw_buffers
- << ":FragmentPrecisionHigh:" << compileResources.FragmentPrecisionHigh
- << ":MaxExpressionComplexity:" << compileResources.MaxExpressionComplexity
- << ":MaxCallStackDepth:" << compileResources.MaxCallStackDepth
- << ":EXT_blend_func_extended:" << compileResources.EXT_blend_func_extended
- << ":EXT_frag_depth:" << compileResources.EXT_frag_depth
- << ":EXT_shader_texture_lod:" << compileResources.EXT_shader_texture_lod
- << ":EXT_shader_framebuffer_fetch:" << compileResources.EXT_shader_framebuffer_fetch
- << ":NV_shader_framebuffer_fetch:" << compileResources.NV_shader_framebuffer_fetch
- << ":ARM_shader_framebuffer_fetch:" << compileResources.ARM_shader_framebuffer_fetch
- << ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors
- << ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors
- << ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset
- << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset
- << ":MaxDualSourceDrawBuffers:" << compileResources.MaxDualSourceDrawBuffers
- << ":NV_draw_buffers:" << compileResources.NV_draw_buffers
- << ":WEBGL_debug_shader_precision:" << compileResources.WEBGL_debug_shader_precision;
+ << ":MaxVertexUniformVectors:" << compileResources.MaxVertexUniformVectors
+ << ":MaxVaryingVectors:" << compileResources.MaxVaryingVectors
+ << ":MaxVertexTextureImageUnits:" << compileResources.MaxVertexTextureImageUnits
+ << ":MaxCombinedTextureImageUnits:" << compileResources.MaxCombinedTextureImageUnits
+ << ":MaxTextureImageUnits:" << compileResources.MaxTextureImageUnits
+ << ":MaxFragmentUniformVectors:" << compileResources.MaxFragmentUniformVectors
+ << ":MaxDrawBuffers:" << compileResources.MaxDrawBuffers
+ << ":OES_standard_derivatives:" << compileResources.OES_standard_derivatives
+ << ":OES_EGL_image_external:" << compileResources.OES_EGL_image_external
+ << ":OES_EGL_image_external_essl3:" << compileResources.OES_EGL_image_external_essl3
+ << ":NV_EGL_stream_consumer_external:" << compileResources.NV_EGL_stream_consumer_external
+ << ":ARB_texture_rectangle:" << compileResources.ARB_texture_rectangle
+ << ":EXT_draw_buffers:" << compileResources.EXT_draw_buffers
+ << ":FragmentPrecisionHigh:" << compileResources.FragmentPrecisionHigh
+ << ":MaxExpressionComplexity:" << compileResources.MaxExpressionComplexity
+ << ":MaxCallStackDepth:" << compileResources.MaxCallStackDepth
+ << ":MaxFunctionParameters:" << compileResources.MaxFunctionParameters
+ << ":EXT_blend_func_extended:" << compileResources.EXT_blend_func_extended
+ << ":EXT_frag_depth:" << compileResources.EXT_frag_depth
+ << ":EXT_shader_texture_lod:" << compileResources.EXT_shader_texture_lod
+ << ":EXT_shader_framebuffer_fetch:" << compileResources.EXT_shader_framebuffer_fetch
+ << ":NV_shader_framebuffer_fetch:" << compileResources.NV_shader_framebuffer_fetch
+ << ":ARM_shader_framebuffer_fetch:" << compileResources.ARM_shader_framebuffer_fetch
+ << ":OVR_multiview:" << compileResources.OVR_multiview
+ << ":EXT_YUV_target:" << compileResources.EXT_YUV_target
+ << ":OES_geometry_shader:" << compileResources.OES_geometry_shader
+ << ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors
+ << ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors
+ << ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset
+ << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset
+ << ":MaxDualSourceDrawBuffers:" << compileResources.MaxDualSourceDrawBuffers
+ << ":MaxViewsOVR:" << compileResources.MaxViewsOVR
+ << ":NV_draw_buffers:" << compileResources.NV_draw_buffers
+ << ":WEBGL_debug_shader_precision:" << compileResources.WEBGL_debug_shader_precision
+ << ":MinProgramTextureGatherOffset:" << compileResources.MinProgramTextureGatherOffset
+ << ":MaxProgramTextureGatherOffset:" << compileResources.MaxProgramTextureGatherOffset
+ << ":MaxImageUnits:" << compileResources.MaxImageUnits
+ << ":MaxVertexImageUniforms:" << compileResources.MaxVertexImageUniforms
+ << ":MaxFragmentImageUniforms:" << compileResources.MaxFragmentImageUniforms
+ << ":MaxComputeImageUniforms:" << compileResources.MaxComputeImageUniforms
+ << ":MaxCombinedImageUniforms:" << compileResources.MaxCombinedImageUniforms
+ << ":MaxCombinedShaderOutputResources:" << compileResources.MaxCombinedShaderOutputResources
+ << ":MaxComputeWorkGroupCountX:" << compileResources.MaxComputeWorkGroupCount[0]
+ << ":MaxComputeWorkGroupCountY:" << compileResources.MaxComputeWorkGroupCount[1]
+ << ":MaxComputeWorkGroupCountZ:" << compileResources.MaxComputeWorkGroupCount[2]
+ << ":MaxComputeWorkGroupSizeX:" << compileResources.MaxComputeWorkGroupSize[0]
+ << ":MaxComputeWorkGroupSizeY:" << compileResources.MaxComputeWorkGroupSize[1]
+ << ":MaxComputeWorkGroupSizeZ:" << compileResources.MaxComputeWorkGroupSize[2]
+ << ":MaxComputeUniformComponents:" << compileResources.MaxComputeUniformComponents
+ << ":MaxComputeTextureImageUnits:" << compileResources.MaxComputeTextureImageUnits
+ << ":MaxComputeAtomicCounters:" << compileResources.MaxComputeAtomicCounters
+ << ":MaxComputeAtomicCounterBuffers:" << compileResources.MaxComputeAtomicCounterBuffers
+ << ":MaxVertexAtomicCounters:" << compileResources.MaxVertexAtomicCounters
+ << ":MaxFragmentAtomicCounters:" << compileResources.MaxFragmentAtomicCounters
+ << ":MaxCombinedAtomicCounters:" << compileResources.MaxCombinedAtomicCounters
+ << ":MaxAtomicCounterBindings:" << compileResources.MaxAtomicCounterBindings
+ << ":MaxVertexAtomicCounterBuffers:" << compileResources.MaxVertexAtomicCounterBuffers
+ << ":MaxFragmentAtomicCounterBuffers:" << compileResources.MaxFragmentAtomicCounterBuffers
+ << ":MaxCombinedAtomicCounterBuffers:" << compileResources.MaxCombinedAtomicCounterBuffers
+ << ":MaxAtomicCounterBufferSize:" << compileResources.MaxAtomicCounterBufferSize
+ << ":MaxGeometryUniformComponents:" << compileResources.MaxGeometryUniformComponents
+ << ":MaxGeometryUniformBlocks:" << compileResources.MaxGeometryUniformBlocks
+ << ":MaxGeometryInputComponents:" << compileResources.MaxGeometryInputComponents
+ << ":MaxGeometryOutputComponents:" << compileResources.MaxGeometryOutputComponents
+ << ":MaxGeometryOutputVertices:" << compileResources.MaxGeometryOutputVertices
+ << ":MaxGeometryTotalOutputComponents:" << compileResources.MaxGeometryTotalOutputComponents
+ << ":MaxGeometryTextureImageUnits:" << compileResources.MaxGeometryTextureImageUnits
+ << ":MaxGeometryAtomicCounterBuffers:" << compileResources.MaxGeometryAtomicCounterBuffers
+ << ":MaxGeometryAtomicCounters:" << compileResources.MaxGeometryAtomicCounters
+ << ":MaxGeometryShaderStorageBlocks:" << compileResources.MaxGeometryShaderStorageBlocks
+ << ":MaxGeometryShaderInvocations:" << compileResources.MaxGeometryShaderInvocations
+ << ":MaxGeometryImageUniforms:" << compileResources.MaxGeometryImageUniforms;
+ // clang-format on
builtInResourcesString = strstream.str();
}
+void TCompiler::collectInterfaceBlocks()
+{
+ ASSERT(interfaceBlocks.empty());
+ interfaceBlocks.reserve(uniformBlocks.size() + shaderStorageBlocks.size() + inBlocks.size());
+ interfaceBlocks.insert(interfaceBlocks.end(), uniformBlocks.begin(), uniformBlocks.end());
+ interfaceBlocks.insert(interfaceBlocks.end(), shaderStorageBlocks.begin(),
+ shaderStorageBlocks.end());
+ interfaceBlocks.insert(interfaceBlocks.end(), inBlocks.begin(), inBlocks.end());
+}
+
void TCompiler::clearResults()
{
arrayBoundsClamper.Cleanup();
infoSink.info.erase();
infoSink.obj.erase();
infoSink.debug.erase();
+ mDiagnostics.resetErrorCount();
attributes.clear();
outputVariables.clear();
uniforms.clear();
- expandedUniforms.clear();
- varyings.clear();
+ inputVaryings.clear();
+ outputVaryings.clear();
interfaceBlocks.clear();
+ uniformBlocks.clear();
+ shaderStorageBlocks.clear();
+ inBlocks.clear();
+ variablesCollected = false;
+ mGLPositionInitialized = false;
+
+ mNumViews = -1;
- builtInFunctionEmulator.Cleanup();
+ mGeometryShaderInputPrimitiveType = EptUndefined;
+ mGeometryShaderOutputPrimitiveType = EptUndefined;
+ mGeometryShaderInvocations = 0;
+ mGeometryShaderMaxVertices = -1;
+
+ builtInFunctionEmulator.cleanup();
nameMap.clear();
- mSourcePath = NULL;
- mTemporaryIndex = 0;
+ mSourcePath = nullptr;
}
bool TCompiler::initCallDag(TIntermNode *root)
{
mCallDag.clear();
- switch (mCallDag.init(root, &infoSink.info))
+ switch (mCallDag.init(root, &mDiagnostics))
{
- case CallDAG::INITDAG_SUCCESS:
- return true;
- case CallDAG::INITDAG_RECURSION:
- infoSink.info.prefix(EPrefixError);
- infoSink.info << "Function recursion detected";
- return false;
- case CallDAG::INITDAG_UNDEFINED:
- infoSink.info.prefix(EPrefixError);
- infoSink.info << "Unimplemented function detected";
- return false;
+ case CallDAG::INITDAG_SUCCESS:
+ return true;
+ case CallDAG::INITDAG_RECURSION:
+ case CallDAG::INITDAG_UNDEFINED:
+ // Error message has already been written out.
+ ASSERT(mDiagnostics.numErrors() > 0);
+ return false;
}
UNREACHABLE();
@@ -553,7 +891,7 @@ bool TCompiler::checkCallDepth()
for (size_t i = 0; i < mCallDag.size(); i++)
{
- int depth = 0;
+ int depth = 0;
auto &record = mCallDag.getRecordFromIndex(i);
for (auto &calleeIndex : record.callees)
@@ -566,19 +904,19 @@ bool TCompiler::checkCallDepth()
if (depth >= maxCallStackDepth)
{
// Trace back the function chain to have a meaningful info log.
- infoSink.info.prefix(EPrefixError);
- infoSink.info << "Call stack too deep (larger than " << maxCallStackDepth
- << ") with the following call chain: " << record.name;
+ std::stringstream errorStream;
+ errorStream << "Call stack too deep (larger than " << maxCallStackDepth
+ << ") with the following call chain: " << record.name;
int currentFunction = static_cast<int>(i);
- int currentDepth = depth;
+ int currentDepth = depth;
while (currentFunction != -1)
{
- infoSink.info << " -> " << mCallDag.getRecordFromIndex(currentFunction).name;
+ errorStream << " -> " << mCallDag.getRecordFromIndex(currentFunction).name;
int nextFunction = -1;
- for (auto& calleeIndex : mCallDag.getRecordFromIndex(currentFunction).callees)
+ for (auto &calleeIndex : mCallDag.getRecordFromIndex(currentFunction).callees)
{
if (depths[calleeIndex] == currentDepth - 1)
{
@@ -590,6 +928,9 @@ bool TCompiler::checkCallDepth()
currentFunction = nextFunction;
}
+ std::string errorStr = errorStream.str();
+ mDiagnostics.globalError(errorStr.c_str());
+
return false;
}
}
@@ -602,15 +943,14 @@ bool TCompiler::tagUsedFunctions()
// Search from main, starting from the end of the DAG as it usually is the root.
for (size_t i = mCallDag.size(); i-- > 0;)
{
- if (mCallDag.getRecordFromIndex(i).name == "main(")
+ if (mCallDag.getRecordFromIndex(i).name == "main")
{
internalTagUsedFunction(i);
return true;
}
}
- infoSink.info.prefix(EPrefixError);
- infoSink.info << "Missing main()\n";
+ mDiagnostics.globalError("Missing main()");
return false;
}
@@ -634,30 +974,35 @@ class TCompiler::UnusedPredicate
{
public:
UnusedPredicate(const CallDAG *callDag, const std::vector<FunctionMetadata> *metadatas)
- : mCallDag(callDag),
- mMetadatas(metadatas)
+ : mCallDag(callDag), mMetadatas(metadatas)
{
}
- bool operator ()(TIntermNode *node)
+ bool operator()(TIntermNode *node)
{
- const TIntermAggregate *asAggregate = node->getAsAggregate();
+ const TIntermFunctionPrototype *asFunctionPrototype = node->getAsFunctionPrototypeNode();
+ const TIntermFunctionDefinition *asFunctionDefinition = node->getAsFunctionDefinition();
+
+ const TFunctionSymbolInfo *functionInfo = nullptr;
- if (asAggregate == nullptr)
+ if (asFunctionDefinition)
{
- return false;
+ functionInfo = asFunctionDefinition->getFunctionSymbolInfo();
}
-
- if (!(asAggregate->getOp() == EOpFunction || asAggregate->getOp() == EOpPrototype))
+ else if (asFunctionPrototype)
+ {
+ functionInfo = asFunctionPrototype->getFunctionSymbolInfo();
+ }
+ if (functionInfo == nullptr)
{
return false;
}
- size_t callDagIndex = mCallDag->findIndex(asAggregate);
+ size_t callDagIndex = mCallDag->findIndex(functionInfo);
if (callDagIndex == CallDAG::InvalidIndex)
{
// This happens only for unimplemented prototypes which are thus unused
- ASSERT(asAggregate->getOp() == EOpPrototype);
+ ASSERT(asFunctionPrototype);
return true;
}
@@ -670,157 +1015,97 @@ class TCompiler::UnusedPredicate
const std::vector<FunctionMetadata> *mMetadatas;
};
-bool TCompiler::pruneUnusedFunctions(TIntermNode *root)
+void TCompiler::pruneUnusedFunctions(TIntermBlock *root)
{
- TIntermAggregate *rootNode = root->getAsAggregate();
- ASSERT(rootNode != nullptr);
-
UnusedPredicate isUnused(&mCallDag, &functionMetadata);
- TIntermSequence *sequence = rootNode->getSequence();
+ TIntermSequence *sequence = root->getSequence();
if (!sequence->empty())
{
- sequence->erase(std::remove_if(sequence->begin(), sequence->end(), isUnused), sequence->end());
+ sequence->erase(std::remove_if(sequence->begin(), sequence->end(), isUnused),
+ sequence->end());
}
-
- return true;
-}
-
-bool TCompiler::validateOutputs(TIntermNode* root)
-{
- ValidateOutputs validateOutputs(getExtensionBehavior(), compileResources.MaxDrawBuffers);
- root->traverse(&validateOutputs);
- return (validateOutputs.validateAndCountErrors(infoSink.info) == 0);
-}
-
-void TCompiler::rewriteCSSShader(TIntermNode* root)
-{
- RenameFunction renamer("main(", "css_main(");
- root->traverse(&renamer);
}
-bool TCompiler::validateLimitations(TIntermNode* root)
+bool TCompiler::limitExpressionComplexity(TIntermBlock *root)
{
- ValidateLimitations validate(shaderType, &infoSink.info);
- root->traverse(&validate);
- return validate.numErrors() == 0;
-}
-
-bool TCompiler::enforceTimingRestrictions(TIntermNode* root, bool outputGraph)
-{
- if (shaderSpec != SH_WEBGL_SPEC)
+ if (!IsASTDepthBelowLimit(root, maxExpressionComplexity))
{
- infoSink.info << "Timing restrictions must be enforced under the WebGL spec.";
+ mDiagnostics.globalError("Expression too complex.");
return false;
}
- if (shaderType == GL_FRAGMENT_SHADER)
- {
- TDependencyGraph graph(root);
-
- // Output any errors first.
- bool success = enforceFragmentShaderTimingRestrictions(graph);
-
- // Then, output the dependency graph.
- if (outputGraph)
- {
- TDependencyGraphOutput output(infoSink.info);
- output.outputAllSpanningTrees(graph);
- }
-
- return success;
- }
- else
- {
- return enforceVertexShaderTimingRestrictions(root);
- }
-}
-
-bool TCompiler::limitExpressionComplexity(TIntermNode* root)
-{
- TMaxDepthTraverser traverser(maxExpressionComplexity+1);
- root->traverse(&traverser);
-
- if (traverser.getMaxDepth() > maxExpressionComplexity)
+ if (!ValidateMaxParameters(root, maxFunctionParameters))
{
- infoSink.info << "Expression too complex.";
+ mDiagnostics.globalError("Function has too many parameters.");
return false;
}
return true;
}
-bool TCompiler::enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph)
+bool TCompiler::shouldCollectVariables(ShCompileOptions compileOptions)
{
- RestrictFragmentShaderTiming restrictor(infoSink.info);
- restrictor.enforceRestrictions(graph);
- return restrictor.numErrors() == 0;
+ return (compileOptions & SH_VARIABLES) != 0;
}
-bool TCompiler::enforceVertexShaderTimingRestrictions(TIntermNode* root)
+bool TCompiler::wereVariablesCollected() const
{
- RestrictVertexShaderTiming restrictor(infoSink.info);
- restrictor.enforceRestrictions(root);
- return restrictor.numErrors() == 0;
+ return variablesCollected;
}
-void TCompiler::collectVariables(TIntermNode* root)
+void TCompiler::initializeGLPosition(TIntermBlock *root)
{
- sh::CollectVariables collect(&attributes,
- &outputVariables,
- &uniforms,
- &varyings,
- &interfaceBlocks,
- hashFunction,
- symbolTable);
- root->traverse(&collect);
-
- // This is for enforcePackingRestriction().
- sh::ExpandUniforms(uniforms, &expandedUniforms);
+ InitVariableList list;
+ sh::ShaderVariable var(GL_FLOAT_VEC4);
+ var.name = "gl_Position";
+ list.push_back(var);
+ InitializeVariables(root, list, &symbolTable, shaderVersion, extensionBehavior, false);
}
-bool TCompiler::enforcePackingRestrictions()
+void TCompiler::useAllMembersInUnusedStandardAndSharedBlocks(TIntermBlock *root)
{
- VariablePacker packer;
- return packer.CheckVariablesWithinPackingLimits(maxUniformVectors, expandedUniforms);
-}
+ sh::InterfaceBlockList list;
-void TCompiler::initializeGLPosition(TIntermNode* root)
-{
- InitializeVariables::InitVariableInfoList variables;
- InitializeVariables::InitVariableInfo var(
- "gl_Position", TType(EbtFloat, EbpUndefined, EvqPosition, 4));
- variables.push_back(var);
- InitializeVariables initializer(variables);
- root->traverse(&initializer);
+ for (auto block : uniformBlocks)
+ {
+ if (!block.staticUse &&
+ (block.layout == sh::BLOCKLAYOUT_STD140 || block.layout == sh::BLOCKLAYOUT_SHARED))
+ {
+ list.push_back(block);
+ }
+ }
+
+ sh::UseInterfaceBlockFields(root, list, symbolTable);
}
-void TCompiler::initializeVaryingsWithoutStaticUse(TIntermNode* root)
+void TCompiler::initializeOutputVariables(TIntermBlock *root)
{
- InitializeVariables::InitVariableInfoList variables;
- for (size_t ii = 0; ii < varyings.size(); ++ii)
+ InitVariableList list;
+ if (shaderType == GL_VERTEX_SHADER || shaderType == GL_GEOMETRY_SHADER_OES)
{
- const sh::Varying& varying = varyings[ii];
- if (varying.staticUse)
- continue;
- unsigned char primarySize = static_cast<unsigned char>(gl::VariableColumnCount(varying.type));
- unsigned char secondarySize = static_cast<unsigned char>(gl::VariableRowCount(varying.type));
- TType type(EbtFloat, EbpUndefined, EvqVaryingOut, primarySize, secondarySize, varying.isArray());
- TString name = varying.name.c_str();
- if (varying.isArray())
+ for (auto var : outputVaryings)
{
- type.setArraySize(varying.arraySize);
- name = name.substr(0, name.find_first_of('['));
+ list.push_back(var);
+ if (var.name == "gl_Position")
+ {
+ ASSERT(!mGLPositionInitialized);
+ mGLPositionInitialized = true;
+ }
}
-
- InitializeVariables::InitVariableInfo var(name, type);
- variables.push_back(var);
}
- InitializeVariables initializer(variables);
- root->traverse(&initializer);
+ else
+ {
+ ASSERT(shaderType == GL_FRAGMENT_SHADER);
+ for (auto var : outputVariables)
+ {
+ list.push_back(var);
+ }
+ }
+ InitializeVariables(root, list, &symbolTable, shaderVersion, extensionBehavior, false);
}
-const TExtensionBehavior& TCompiler::getExtensionBehavior() const
+const TExtensionBehavior &TCompiler::getExtensionBehavior() const
{
return extensionBehavior;
}
@@ -830,12 +1115,12 @@ const char *TCompiler::getSourcePath() const
return mSourcePath;
}
-const ShBuiltInResources& TCompiler::getResources() const
+const ShBuiltInResources &TCompiler::getResources() const
{
return compileResources;
}
-const ArrayBoundsClamper& TCompiler::getArrayBoundsClamper() const
+const ArrayBoundsClamper &TCompiler::getArrayBoundsClamper() const
{
return arrayBoundsClamper;
}
@@ -845,14 +1130,40 @@ ShArrayIndexClampingStrategy TCompiler::getArrayIndexClampingStrategy() const
return clampingStrategy;
}
-const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
+const BuiltInFunctionEmulator &TCompiler::getBuiltInFunctionEmulator() const
{
return builtInFunctionEmulator;
}
-void TCompiler::writePragma()
+void TCompiler::writePragma(ShCompileOptions compileOptions)
+{
+ if (!(compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL))
+ {
+ TInfoSinkBase &sink = infoSink.obj;
+ if (mPragma.stdgl.invariantAll)
+ sink << "#pragma STDGL invariant(all)\n";
+ }
+}
+
+bool TCompiler::isVaryingDefined(const char *varyingName)
{
- TInfoSinkBase &sink = infoSink.obj;
- if (mPragma.stdgl.invariantAll)
- sink << "#pragma STDGL invariant(all)\n";
+ ASSERT(variablesCollected);
+ for (size_t ii = 0; ii < inputVaryings.size(); ++ii)
+ {
+ if (inputVaryings[ii].name == varyingName)
+ {
+ return true;
+ }
+ }
+ for (size_t ii = 0; ii < outputVaryings.size(); ++ii)
+ {
+ if (outputVaryings[ii].name == varyingName)
+ {
+ return true;
+ }
+ }
+
+ return false;
}
+
+} // namespace sh