Commit 0ffc441e by Olli Etuaho Committed by Commit Bot

Initialize uninitialized globals in GLSL output

Initializing globals is done by the DeferGlobalInitializers AST transformation, which makes sure that the global variable init proceeds in the correct order. This is important since some global variables may use other uninitialized globals in their initializers. The global variable init is only done in case the WebGL shader spec is being followed. This avoids adding global initializers twice in case the same shader goes through multiple translations, assuming only one of them is a WebGL shader translation. BUG=angleproject:1966 TEST=angle_end2end_tests, WebGL conformance tests Change-Id: Iea701d3ae40edc906abd87303f2aa27fd23bf55a Reviewed-on: https://chromium-review.googlesource.com/509689 Commit-Queue: Olli Etuaho <oetuaho@nvidia.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 0a82f2fa
......@@ -475,7 +475,7 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
if (success)
{
DeferGlobalInitializers(root);
DeferGlobalInitializers(root, needToInitializeGlobalsInAST());
}
if (success && (compileOptions & SH_INITIALIZE_UNINITIALIZED_LOCALS) && getOutputType())
......
......@@ -172,6 +172,7 @@ 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;
......
......@@ -9,10 +9,13 @@
// unfolded into if statements in HLSL - this kind of steps should be done after
// DeferGlobalInitializers is run.
//
// It can also initialize all uninitialized globals.
//
#include "compiler/translator/DeferGlobalInitializers.h"
#include "compiler/translator/FindMain.h"
#include "compiler/translator/InitializeVariables.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/SymbolTable.h"
......@@ -23,6 +26,7 @@ namespace
{
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
......@@ -77,6 +81,17 @@ void GetDeferredInitializers(TIntermDeclaration *declaration,
declaration->replaceChildNode(init, symbolNode);
}
}
else if (initializeUninitializedGlobals)
{
TIntermSymbol *symbolNode = declarator->getAsSymbolNode();
ASSERT(symbolNode);
if (symbolNode->getQualifier() == EvqGlobal && symbolNode->getSymbol() != "")
{
TIntermSequence *initCode = CreateInitCode(symbolNode);
deferredInitializersOut->insert(deferredInitializersOut->end(), initCode->begin(),
initCode->end());
}
}
}
}
......@@ -95,18 +110,19 @@ void InsertInitCodeToMain(TIntermBlock *root, TIntermSequence *deferredInitializ
} // namespace
void DeferGlobalInitializers(TIntermBlock *root)
void DeferGlobalInitializers(TIntermBlock *root, bool initializeUninitializedGlobals)
{
TIntermSequence *deferredInitializers = new TIntermSequence();
// Loop over all global statements and process the declarations. This is simpler than using a
// traverser.
for (TIntermNode *declaration : *root->getSequence())
for (TIntermNode *statement : *root->getSequence())
{
TIntermDeclaration *asVariableDeclaration = declaration->getAsDeclarationNode();
if (asVariableDeclaration)
TIntermDeclaration *declaration = statement->getAsDeclarationNode();
if (declaration)
{
GetDeferredInitializers(asVariableDeclaration, deferredInitializers);
GetDeferredInitializers(declaration, initializeUninitializedGlobals,
deferredInitializers);
}
}
......
......@@ -9,6 +9,8 @@
// unfolded into if statements in HLSL - this kind of steps should be done after
// DeferGlobalInitializers is run.
//
// It can also initialize all uninitialized globals.
//
#ifndef COMPILER_TRANSLATOR_DEFERGLOBALINITIALIZERS_H_
#define COMPILER_TRANSLATOR_DEFERGLOBALINITIALIZERS_H_
......@@ -17,7 +19,7 @@ class TIntermBlock;
namespace sh
{
void DeferGlobalInitializers(TIntermBlock *root);
void DeferGlobalInitializers(TIntermBlock *root, bool initializeUninitializedGlobals);
} // namespace sh
#endif // COMPILER_TRANSLATOR_DEFERGLOBALINITIALIZERS_H_
......@@ -30,6 +30,9 @@ 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> mInterfaceBlockRegisterMap;
std::map<std::string, unsigned int> mUniformRegisterMap;
};
......
......@@ -2960,6 +2960,51 @@ TEST_P(GLSLTest_ES3, UninitializedNamelessStructInForInitStatement)
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// Test that uninitialized global variables are initialized to 0.
TEST_P(WebGLGLSLTest, InitUninitializedGlobals)
{
const std::string &fragmentShader =
"precision mediump float;\n"
"int result;\n"
"int i[2], j = i[0] + 1;\n"
"void main()\n"
"{\n"
" result += j;\n"
" if (result == 1)\n"
" {\n"
" gl_FragColor = vec4(0, 1, 0, 1);\n"
" }\n"
" else\n"
" {\n"
" gl_FragColor = vec4(1, 0, 0, 1);\n"
" }\n"
"}\n";
ANGLE_GL_PROGRAM(program, mSimpleVSSource, fragmentShader);
drawQuad(program.get(), "inputAttribute", 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// Test that an uninitialized nameless struct in the global scope works.
TEST_P(WebGLGLSLTest, UninitializedNamelessStructInGlobalScope)
{
const std::string &fragmentShader =
"precision mediump float;\n"
"struct { float q; } b;\n"
"void main()\n"
"{\n"
" gl_FragColor = vec4(1, 0, 0, 1);\n"
" if (b.q == 0.0)\n"
" {\n"
" gl_FragColor = vec4(0, 1, 0, 1);\n"
" }\n"
"}\n";
ANGLE_GL_PROGRAM(program, mSimpleVSSource, fragmentShader);
drawQuad(program.get(), "inputAttribute", 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_INSTANTIATE_TEST(GLSLTest,
ES2_D3D9(),
......
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