Commit a16a84f3 by Olli Etuaho Committed by Commit Bot

GLSL: Fix initializing globals declared after main()

Initialize globals in a separate function instead of a block in the beginning of main(). This way it works also for globals declared after main(). BUG=chromium:764036 TEST=angle_end2end_tests Change-Id: I2fcbb97d046589301287757dc3dde5471172a3f6 Reviewed-on: https://chromium-review.googlesource.com/663158 Commit-Queue: Corentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent 5b03f475
...@@ -523,7 +523,7 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[], ...@@ -523,7 +523,7 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
if (success) if (success)
{ {
DeferGlobalInitializers(root, needToInitializeGlobalsInAST()); DeferGlobalInitializers(root, needToInitializeGlobalsInAST(), &symbolTable);
} }
if (success && (compileOptions & SH_INITIALIZE_UNINITIALIZED_LOCALS) && getOutputType()) if (success && (compileOptions & SH_INITIALIZE_UNINITIALIZED_LOCALS) && getOutputType())
......
...@@ -3,11 +3,12 @@ ...@@ -3,11 +3,12 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// //
// DeferGlobalInitializers is an AST traverser that moves global initializers into a block in the // DeferGlobalInitializers is an AST traverser that moves global initializers into a separate
// beginning of main(). This enables initialization of globals with uniforms or non-constant // function that is called in the beginning of main(). This enables initialization of globals with
// globals, as allowed by the WebGL spec. Some initializers referencing non-constants may need to be // uniforms or non-constant globals, as allowed by the WebGL spec. Some initializers referencing
// unfolded into if statements in HLSL - this kind of steps should be done after // non-constants may need to be unfolded into if statements in HLSL - this kind of steps should be
// DeferGlobalInitializers is run. // done after DeferGlobalInitializers is run. Note that it's important that the function definition
// is at the end of the shader, as some globals may be declared after main().
// //
// It can also initialize all uninitialized globals. // It can also initialize all uninitialized globals.
// //
...@@ -17,6 +18,7 @@ ...@@ -17,6 +18,7 @@
#include "compiler/translator/FindMain.h" #include "compiler/translator/FindMain.h"
#include "compiler/translator/InitializeVariables.h" #include "compiler/translator/InitializeVariables.h"
#include "compiler/translator/IntermNode.h" #include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermNode_util.h"
#include "compiler/translator/SymbolTable.h" #include "compiler/translator/SymbolTable.h"
namespace sh namespace sh
...@@ -100,19 +102,36 @@ void GetDeferredInitializers(TIntermDeclaration *declaration, ...@@ -100,19 +102,36 @@ void GetDeferredInitializers(TIntermDeclaration *declaration,
} }
} }
void InsertInitCodeToMain(TIntermBlock *root, TIntermSequence *deferredInitializers) void InsertInitCallToMain(TIntermBlock *root,
TIntermSequence *deferredInitializers,
TSymbolTable *symbolTable)
{ {
// Insert init code as a block to the beginning of the main() function.
TIntermBlock *initGlobalsBlock = new TIntermBlock(); TIntermBlock *initGlobalsBlock = new TIntermBlock();
initGlobalsBlock->getSequence()->swap(*deferredInitializers); initGlobalsBlock->getSequence()->swap(*deferredInitializers);
TSymbolUniqueId initGlobalsFunctionId(symbolTable);
const char *kInitGlobalsFunctionName = "initGlobals";
TIntermFunctionPrototype *initGlobalsFunctionPrototype =
CreateInternalFunctionPrototypeNode(TType(), kInitGlobalsFunctionName, initGlobalsFunctionId);
root->getSequence()->insert(root->getSequence()->begin(), initGlobalsFunctionPrototype);
TIntermFunctionDefinition *initGlobalsFunctionDefinition = CreateInternalFunctionDefinitionNode(
TType(), kInitGlobalsFunctionName, initGlobalsBlock, initGlobalsFunctionId);
root->appendStatement(initGlobalsFunctionDefinition);
TIntermAggregate *initGlobalsCall = CreateInternalFunctionCallNode(
TType(), kInitGlobalsFunctionName, initGlobalsFunctionId, new TIntermSequence());
TIntermBlock *mainBody = FindMainBody(root); TIntermBlock *mainBody = FindMainBody(root);
mainBody->getSequence()->insert(mainBody->getSequence()->begin(), initGlobalsBlock); mainBody->getSequence()->insert(mainBody->getSequence()->begin(), initGlobalsCall);
} }
} // namespace } // namespace
void DeferGlobalInitializers(TIntermBlock *root, bool initializeUninitializedGlobals) void DeferGlobalInitializers(TIntermBlock *root,
bool initializeUninitializedGlobals,
TSymbolTable *symbolTable)
{ {
TIntermSequence *deferredInitializers = new TIntermSequence(); TIntermSequence *deferredInitializers = new TIntermSequence();
...@@ -131,7 +150,7 @@ void DeferGlobalInitializers(TIntermBlock *root, bool initializeUninitializedGlo ...@@ -131,7 +150,7 @@ void DeferGlobalInitializers(TIntermBlock *root, bool initializeUninitializedGlo
// Add the function with initialization and the call to that. // Add the function with initialization and the call to that.
if (!deferredInitializers->empty()) if (!deferredInitializers->empty())
{ {
InsertInitCodeToMain(root, deferredInitializers); InsertInitCallToMain(root, deferredInitializers, symbolTable);
} }
} }
......
...@@ -3,11 +3,12 @@ ...@@ -3,11 +3,12 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// //
// DeferGlobalInitializers is an AST traverser that moves global initializers into a block in the // DeferGlobalInitializers is an AST traverser that moves global initializers into a separate
// beginning of main(). This enables initialization of globals with uniforms or non-constant // function that is called in the beginning of main(). This enables initialization of globals with
// globals, as allowed by the WebGL spec. Some initializers referencing non-constants may need to be // uniforms or non-constant globals, as allowed by the WebGL spec. Some initializers referencing
// unfolded into if statements in HLSL - this kind of steps should be done after // non-constants may need to be unfolded into if statements in HLSL - this kind of steps should be
// DeferGlobalInitializers is run. // done after DeferGlobalInitializers is run. Note that it's important that the function definition
// is at the end of the shader, as some globals may be declared after main().
// //
// It can also initialize all uninitialized globals. // It can also initialize all uninitialized globals.
// //
...@@ -15,11 +16,16 @@ ...@@ -15,11 +16,16 @@
#ifndef COMPILER_TRANSLATOR_DEFERGLOBALINITIALIZERS_H_ #ifndef COMPILER_TRANSLATOR_DEFERGLOBALINITIALIZERS_H_
#define COMPILER_TRANSLATOR_DEFERGLOBALINITIALIZERS_H_ #define COMPILER_TRANSLATOR_DEFERGLOBALINITIALIZERS_H_
class TIntermBlock;
namespace sh namespace sh
{ {
void DeferGlobalInitializers(TIntermBlock *root, bool initializeUninitializedGlobals);
class TIntermBlock;
class TSymbolTable;
void DeferGlobalInitializers(TIntermBlock *root,
bool initializeUninitializedGlobals,
TSymbolTable *symbolTable);
} // namespace sh } // namespace sh
#endif // COMPILER_TRANSLATOR_DEFERGLOBALINITIALIZERS_H_ #endif // COMPILER_TRANSLATOR_DEFERGLOBALINITIALIZERS_H_
...@@ -3375,6 +3375,34 @@ TEST_P(GLSLTest, StructWithSamplerArrayAsFunctionArg) ...@@ -3375,6 +3375,34 @@ TEST_P(GLSLTest, StructWithSamplerArrayAsFunctionArg)
EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::green); EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::green);
} }
// Test that a global variable declared after main() works. This is a regression test for an issue
// in global variable initialization.
TEST_P(WebGLGLSLTest, GlobalVariableDeclaredAfterMain)
{
const std::string &fragmentShader =
"precision mediump float;\n"
"int getFoo();\n"
"uniform int u_zero;\n"
"void main()\n"
"{\n"
" gl_FragColor = vec4(1, 0, 0, 1);\n"
" if (getFoo() == 0)\n"
" {\n"
" gl_FragColor = vec4(0, 1, 0, 1);\n"
" }\n"
"}\n"
"int foo;\n"
"int getFoo()\n"
"{\n"
" foo = u_zero;\n"
" return foo;\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. // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_INSTANTIATE_TEST(GLSLTest, ANGLE_INSTANTIATE_TEST(GLSLTest,
ES2_D3D9(), 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