Commit b5601eb6 by Olli Etuaho Committed by Commit Bot

Only initialize globals if initialization flag is set

This avoids the possibility of initializing globals twice in Chromium. Now we also never initialize variables redundantly in case we're writing HLSL output. This was already the intent of the code before, but a mistake had slipped in and the code didn't actually check the output type properly. This also simplifies DeferGlobalInitializers by running it after SeparateDeclarations. BUG=chromium:735497 TEST=WebGL conformance tests Change-Id: I95036a24ac8cf18113755510376a2fca286b3ee6 Reviewed-on: https://chromium-review.googlesource.com/771555Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent 8957b6c0
......@@ -218,8 +218,8 @@ const ShCompileOptions SH_EMULATE_ATAN2_FLOAT_FUNCTION = UINT64_C(1) << 30;
// "uniform highp uint ViewID_OVR".
const ShCompileOptions SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM = UINT64_C(1) << 31;
// Set to initialize uninitialized local variables. Should only be used with GLSL output. In HLSL
// output variables are initialized regardless of if this flag is set.
// Set to initialize uninitialized local and global temporary variables. Should only be used with
// GLSL output. In HLSL output variables are initialized regardless of if this flag is set.
const ShCompileOptions SH_INITIALIZE_UNINITIALIZED_LOCALS = UINT64_C(1) << 32;
// The flag modifies the shader in the following way:
......
......@@ -45,6 +45,7 @@
#include "compiler/translator/ValidateVaryingLocations.h"
#include "compiler/translator/VariablePacker.h"
#include "compiler/translator/VectorizeVectorScalarArithmetic.h"
#include "compiler/translator/util.h"
#include "third_party/compiler/ArrayBoundsClamper.h"
namespace sh
......@@ -571,8 +572,6 @@ bool TCompiler::checkAndSimplifyAST(TIntermBlock *root,
&symbolTable, shaderVersion);
}
DeferGlobalInitializers(root, needToInitializeGlobalsInAST(), &symbolTable);
// 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.
......@@ -590,7 +589,15 @@ bool TCompiler::checkAndSimplifyAST(TIntermBlock *root,
RemoveArrayLengthMethod(root);
if ((compileOptions & SH_INITIALIZE_UNINITIALIZED_LOCALS) && getOutputType())
// 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());
DeferGlobalInitializers(root, initializeLocalsAndGlobals, &symbolTable);
if (initializeLocalsAndGlobals)
{
// Initialize uninitialized local variables.
// In some cases initializing can generate extra statements in the parent block, such as
......
......@@ -189,7 +189,6 @@ class TCompiler : public TShHandleBase
virtual bool shouldFlattenPragmaStdglInvariantAll() = 0;
virtual bool shouldCollectVariables(ShCompileOptions compileOptions);
virtual bool needToInitializeGlobalsInAST() const { return IsWebGLBasedSpec(shaderSpec); }
bool wereVariablesCollected() const;
std::vector<sh::Attribute> attributes;
......
......@@ -31,73 +31,59 @@ void GetDeferredInitializers(TIntermDeclaration *declaration,
bool initializeUninitializedGlobals,
TIntermSequence *deferredInitializersOut)
{
// We iterate with an index instead of using an iterator since we're replacing the children of
// declaration inside the loop.
for (size_t i = 0; i < declaration->getSequence()->size(); ++i)
// SeparateDeclarations should have already been run.
ASSERT(declaration->getSequence()->size() == 1);
TIntermNode *declarator = declaration->getSequence()->back();
TIntermBinary *init = declarator->getAsBinaryNode();
if (init)
{
TIntermNode *declarator = declaration->getSequence()->at(i);
TIntermBinary *init = declarator->getAsBinaryNode();
if (init)
{
TIntermSymbol *symbolNode = init->getLeft()->getAsSymbolNode();
ASSERT(symbolNode);
TIntermTyped *expression = init->getRight();
TIntermSymbol *symbolNode = init->getLeft()->getAsSymbolNode();
ASSERT(symbolNode);
TIntermTyped *expression = init->getRight();
if ((expression->getQualifier() != EvqConst ||
(expression->getAsConstantUnion() == nullptr &&
!expression->isConstructorWithOnlyConstantUnionParameters())))
if ((expression->getQualifier() != EvqConst ||
(expression->getAsConstantUnion() == nullptr &&
!expression->isConstructorWithOnlyConstantUnionParameters())))
{
// For variables which are not constant, defer their real initialization until
// after we initialize uniforms.
// Deferral is done also in any cases where the variable has not been constant
// folded, since otherwise there's a chance that HLSL output will generate extra
// statements from the initializer expression.
// Change const global to a regular global if its initialization is deferred.
// This can happen if ANGLE has not been able to fold the constant expression used
// as an initializer.
ASSERT(symbolNode->getQualifier() == EvqConst ||
symbolNode->getQualifier() == EvqGlobal);
if (symbolNode->getQualifier() == EvqConst)
{
// For variables which are not constant, defer their real initialization until
// after we initialize uniforms.
// Deferral is done also in any cases where the variable has not been constant
// folded, since otherwise there's a chance that HLSL output will generate extra
// statements from the initializer expression.
TIntermBinary *deferredInit =
new TIntermBinary(EOpAssign, symbolNode->deepCopy(), init->getRight());
deferredInitializersOut->push_back(deferredInit);
// Change const global to a regular global if its initialization is deferred.
// This can happen if ANGLE has not been able to fold the constant expression used
// as an initializer.
ASSERT(symbolNode->getQualifier() == EvqConst ||
symbolNode->getQualifier() == EvqGlobal);
if (symbolNode->getQualifier() == EvqConst)
{
// All of the siblings in the same declaration need to have consistent
// qualifiers.
auto *siblings = declaration->getSequence();
for (TIntermNode *siblingNode : *siblings)
{
TIntermBinary *siblingBinary = siblingNode->getAsBinaryNode();
if (siblingBinary)
{
ASSERT(siblingBinary->getOp() == EOpInitialize);
siblingBinary->getLeft()->getTypePointer()->setQualifier(EvqGlobal);
}
siblingNode->getAsTyped()->getTypePointer()->setQualifier(EvqGlobal);
}
// This node is one of the siblings.
ASSERT(symbolNode->getQualifier() == EvqGlobal);
}
// Remove the initializer from the global scope and just declare the global instead.
declaration->replaceChildNode(init, symbolNode);
symbolNode->getTypePointer()->setQualifier(EvqGlobal);
}
TIntermBinary *deferredInit =
new TIntermBinary(EOpAssign, symbolNode->deepCopy(), init->getRight());
deferredInitializersOut->push_back(deferredInit);
// Remove the initializer from the global scope and just declare the global instead.
declaration->replaceChildNode(init, symbolNode);
}
else if (initializeUninitializedGlobals)
{
TIntermSymbol *symbolNode = declarator->getAsSymbolNode();
ASSERT(symbolNode);
}
else if (initializeUninitializedGlobals)
{
TIntermSymbol *symbolNode = declarator->getAsSymbolNode();
ASSERT(symbolNode);
// Ignore ANGLE internal variables.
if (symbolNode->getName().isInternal())
continue;
// Ignore ANGLE internal variables.
if (symbolNode->getName().isInternal())
return;
if (symbolNode->getQualifier() == EvqGlobal && symbolNode->getSymbol() != "")
{
TIntermSequence *initCode = CreateInitCode(symbolNode);
deferredInitializersOut->insert(deferredInitializersOut->end(), initCode->begin(),
initCode->end());
}
if (symbolNode->getQualifier() == EvqGlobal && symbolNode->getSymbol() != "")
{
TIntermSequence *initCode = CreateInitCode(symbolNode);
deferredInitializersOut->insert(deferredInitializersOut->end(), initCode->begin(),
initCode->end());
}
}
}
......
......@@ -32,9 +32,6 @@ class TranslatorHLSL : public TCompiler
// collectVariables needs to be run always so registers can be assigned.
bool shouldCollectVariables(ShCompileOptions compileOptions) override { return true; }
// Globals are initialized in output so it is redundant to initialize them in the AST.
bool needToInitializeGlobalsInAST() const override { return false; }
std::map<std::string, unsigned int> mUniformBlockRegisterMap;
std::map<std::string, unsigned int> mUniformRegisterMap;
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment