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[],
if (success)
{
DeferGlobalInitializers(root, needToInitializeGlobalsInAST());
DeferGlobalInitializers(root, needToInitializeGlobalsInAST(), &symbolTable);
}
if (success && (compileOptions & SH_INITIALIZE_UNINITIALIZED_LOCALS) && getOutputType())
......
......@@ -3,11 +3,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// DeferGlobalInitializers is an AST traverser that moves global initializers into a block in the
// beginning of main(). This enables initialization of globals with uniforms or non-constant
// globals, as allowed by the WebGL spec. Some initializers referencing non-constants may need to be
// unfolded into if statements in HLSL - this kind of steps should be done after
// DeferGlobalInitializers is run.
// DeferGlobalInitializers is an AST traverser that moves global initializers into a separate
// function that is called in the beginning of main(). This enables initialization of globals with
// uniforms or non-constant globals, as allowed by the WebGL spec. Some initializers referencing
// non-constants may need to be unfolded into if statements in HLSL - this kind of steps should be
// 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.
//
......@@ -17,6 +18,7 @@
#include "compiler/translator/FindMain.h"
#include "compiler/translator/InitializeVariables.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/IntermNode_util.h"
#include "compiler/translator/SymbolTable.h"
namespace sh
......@@ -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();
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);
mainBody->getSequence()->insert(mainBody->getSequence()->begin(), initGlobalsBlock);
mainBody->getSequence()->insert(mainBody->getSequence()->begin(), initGlobalsCall);
}
} // namespace
void DeferGlobalInitializers(TIntermBlock *root, bool initializeUninitializedGlobals)
void DeferGlobalInitializers(TIntermBlock *root,
bool initializeUninitializedGlobals,
TSymbolTable *symbolTable)
{
TIntermSequence *deferredInitializers = new TIntermSequence();
......@@ -131,7 +150,7 @@ void DeferGlobalInitializers(TIntermBlock *root, bool initializeUninitializedGlo
// Add the function with initialization and the call to that.
if (!deferredInitializers->empty())
{
InsertInitCodeToMain(root, deferredInitializers);
InsertInitCallToMain(root, deferredInitializers, symbolTable);
}
}
......
......@@ -3,11 +3,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// DeferGlobalInitializers is an AST traverser that moves global initializers into a block in the
// beginning of main(). This enables initialization of globals with uniforms or non-constant
// globals, as allowed by the WebGL spec. Some initializers referencing non-constants may need to be
// unfolded into if statements in HLSL - this kind of steps should be done after
// DeferGlobalInitializers is run.
// DeferGlobalInitializers is an AST traverser that moves global initializers into a separate
// function that is called in the beginning of main(). This enables initialization of globals with
// uniforms or non-constant globals, as allowed by the WebGL spec. Some initializers referencing
// non-constants may need to be unfolded into if statements in HLSL - this kind of steps should be
// 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.
//
......@@ -15,11 +16,16 @@
#ifndef COMPILER_TRANSLATOR_DEFERGLOBALINITIALIZERS_H_
#define COMPILER_TRANSLATOR_DEFERGLOBALINITIALIZERS_H_
class TIntermBlock;
namespace sh
{
void DeferGlobalInitializers(TIntermBlock *root, bool initializeUninitializedGlobals);
class TIntermBlock;
class TSymbolTable;
void DeferGlobalInitializers(TIntermBlock *root,
bool initializeUninitializedGlobals,
TSymbolTable *symbolTable);
} // namespace sh
#endif // COMPILER_TRANSLATOR_DEFERGLOBALINITIALIZERS_H_
......@@ -3375,6 +3375,34 @@ TEST_P(GLSLTest, StructWithSamplerArrayAsFunctionArg)
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.
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