Commit e145def0 by Martin Radev Committed by Commit Bot

Propagate correct type to the lvalue in an output variable initializer

With the SH_INIT_OUTPUT_VARIABLES option enabled, vertex and fragment shader outputs get initialized with zeros at the beginning of main. However, previous to this patch the lvalues in the binary expression did not receive the correct type. This can lead to incorrect modifications of the AST in subsequent stages or incorrect output code from the translator. The patch addresses the issue by copying the type information from the symbol table. BUG=angleproject:2081 TEST=angle_unittests TEST=angle_end2end_tests Change-Id: I9e062376bcfad7d57b637a5248caebce1c9a0688 Reviewed-on: https://chromium-review.googlesource.com/544982 Commit-Queue: Olli Etuaho <oetuaho@nvidia.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent ff526f14
...@@ -937,7 +937,7 @@ void TCompiler::initializeGLPosition(TIntermBlock *root) ...@@ -937,7 +937,7 @@ void TCompiler::initializeGLPosition(TIntermBlock *root)
sh::ShaderVariable var(GL_FLOAT_VEC4, 0); sh::ShaderVariable var(GL_FLOAT_VEC4, 0);
var.name = "gl_Position"; var.name = "gl_Position";
list.push_back(var); list.push_back(var);
InitializeVariables(root, list, symbolTable); InitializeVariables(root, list, symbolTable, shaderVersion, shaderSpec, extensionBehavior);
} }
void TCompiler::useAllMembersInUnusedStandardAndSharedBlocks(TIntermBlock *root) void TCompiler::useAllMembersInUnusedStandardAndSharedBlocks(TIntermBlock *root)
...@@ -974,7 +974,7 @@ void TCompiler::initializeOutputVariables(TIntermBlock *root) ...@@ -974,7 +974,7 @@ void TCompiler::initializeOutputVariables(TIntermBlock *root)
list.push_back(var); list.push_back(var);
} }
} }
InitializeVariables(root, list, symbolTable); InitializeVariables(root, list, symbolTable, shaderVersion, shaderSpec, extensionBehavior);
} }
const TExtensionBehavior &TCompiler::getExtensionBehavior() const const TExtensionBehavior &TCompiler::getExtensionBehavior() const
......
...@@ -84,36 +84,50 @@ void AddArrayZeroInitSequence(const TIntermTyped *initializedNode, TIntermSequen ...@@ -84,36 +84,50 @@ void AddArrayZeroInitSequence(const TIntermTyped *initializedNode, TIntermSequen
void InsertInitCode(TIntermSequence *mainBody, void InsertInitCode(TIntermSequence *mainBody,
const InitVariableList &variables, const InitVariableList &variables,
const TSymbolTable &symbolTable) const TSymbolTable &symbolTable,
int shaderVersion,
ShShaderSpec shaderSpec,
const TExtensionBehavior &extensionBehavior)
{ {
for (const auto &var : variables) for (const auto &var : variables)
{ {
TString name = TString(var.name.c_str()); TString name = TString(var.name.c_str());
size_t pos = name.find_last_of('[');
TIntermSymbol *initializedSymbol = nullptr; if (pos != TString::npos)
if (var.isArray())
{ {
size_t pos = name.find_last_of('['); name = name.substr(0, pos);
if (pos != TString::npos)
{
name = name.substr(0, pos);
}
TType arrayType = sh::GetShaderVariableBasicType(var);
arrayType.setArraySize(var.elementCount());
initializedSymbol = new TIntermSymbol(0, name, arrayType);
} }
else if (var.isStruct())
{
TVariable *structInfo = reinterpret_cast<TVariable *>(symbolTable.findGlobal(name));
ASSERT(structInfo);
initializedSymbol = new TIntermSymbol(0, name, structInfo->getType()); const TVariable *symbolInfo = nullptr;
if (var.isBuiltIn())
{
symbolInfo =
reinterpret_cast<const TVariable *>(symbolTable.findBuiltIn(name, shaderVersion));
} }
else else
{ {
TType type = sh::GetShaderVariableBasicType(var); symbolInfo = reinterpret_cast<const TVariable *>(symbolTable.findGlobal(name));
initializedSymbol = new TIntermSymbol(0, name, type);
} }
ASSERT(symbolInfo != nullptr);
TType type = symbolInfo->getType();
if (type.getQualifier() == EvqFragData &&
(shaderSpec == SH_WEBGL2_SPEC ||
!IsExtensionEnabled(extensionBehavior, "GL_EXT_draw_buffers")))
{
// Adjust the number of attachment indices which can be initialized according to the
// WebGL2 spec and extension behavior:
// - WebGL2 spec, Editor's draft May 31, 5.13 GLSL ES
// 1.00 Fragment Shader Output: "A fragment shader written in The OpenGL ES Shading
// Language, Version 1.00, that statically assigns a value to gl_FragData[n] where n
// does not equal constant value 0 must fail to compile in the WebGL 2.0 API.".
// This excerpt limits the initialization of gl_FragData to only the 0th index.
// - If GL_EXT_draw_buffers is disabled, only the 0th index of gl_FragData can be
// written to.
type.setArraySize(1u);
}
TIntermSymbol *initializedSymbol = new TIntermSymbol(0, name, type);
TIntermSequence *initCode = CreateInitCode(initializedSymbol); TIntermSequence *initCode = CreateInitCode(initializedSymbol);
mainBody->insert(mainBody->begin(), initCode->begin(), initCode->end()); mainBody->insert(mainBody->begin(), initCode->begin(), initCode->end());
} }
...@@ -204,12 +218,17 @@ void InitializeUninitializedLocals(TIntermBlock *root, int shaderVersion) ...@@ -204,12 +218,17 @@ void InitializeUninitializedLocals(TIntermBlock *root, int shaderVersion)
void InitializeVariables(TIntermBlock *root, void InitializeVariables(TIntermBlock *root,
const InitVariableList &vars, const InitVariableList &vars,
const TSymbolTable &symbolTable) const TSymbolTable &symbolTable,
int shaderVersion,
ShShaderSpec shaderSpec,
const TExtensionBehavior &extensionBehavior)
{ {
TIntermFunctionDefinition *main = FindMain(root); TIntermFunctionDefinition *main = FindMain(root);
ASSERT(main != nullptr); ASSERT(main != nullptr);
TIntermBlock *body = main->getBody(); TIntermBlock *body = main->getBody();
InsertInitCode(body->getSequence(), vars, symbolTable); InsertInitCode(body->getSequence(), vars, symbolTable, shaderVersion, shaderSpec,
extensionBehavior);
} }
} // namespace sh } // namespace sh
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <GLSLANG/ShaderLang.h> #include <GLSLANG/ShaderLang.h>
#include "compiler/translator/ExtensionBehavior.h"
#include "compiler/translator/IntermNode.h" #include "compiler/translator/IntermNode.h"
namespace sh namespace sh
...@@ -24,15 +25,20 @@ TIntermSequence *CreateInitCode(const TIntermSymbol *initializedSymbol); ...@@ -24,15 +25,20 @@ TIntermSequence *CreateInitCode(const TIntermSymbol *initializedSymbol);
// Initialize all uninitialized local variables, so that undefined behavior is avoided. // Initialize all uninitialized local variables, so that undefined behavior is avoided.
void InitializeUninitializedLocals(TIntermBlock *root, int shaderVersion); void InitializeUninitializedLocals(TIntermBlock *root, int shaderVersion);
// This function can initialize all the types that CreateInitCode is able to initialize. For struct // This function can initialize all the types that CreateInitCode is able to initialize. All
// typed variables it requires that the struct is found from the symbolTable, which is usually not // variables must be globals which can be found in the symbol table. For now it is used for the
// the case for locally defined struct types. // following two scenarios:
// For now it is used for the following two scenarios: // 1. Initializing gl_Position;
// 1. initializing gl_Position; // 2. Initializing output variables referred to in the shader source.
// 2. initializing ESSL 3.00 shaders' output variables. // Note: The type of each lvalue in an initializer is retrieved from the symbol table. gl_FragData
// requires special handling because the number of indices which can be initialized is determined by
// the API spec and extension support.
void InitializeVariables(TIntermBlock *root, void InitializeVariables(TIntermBlock *root,
const InitVariableList &vars, const InitVariableList &vars,
const TSymbolTable &symbolTable); const TSymbolTable &symbolTable,
int shaderVersion,
ShShaderSpec shaderSpec,
const TExtensionBehavior &extensionBehavior);
} // namespace sh } // namespace sh
......
...@@ -63,6 +63,7 @@ ...@@ -63,6 +63,7 @@
'<(angle_path)/src/tests/compiler_tests/FloatLex_test.cpp', '<(angle_path)/src/tests/compiler_tests/FloatLex_test.cpp',
'<(angle_path)/src/tests/compiler_tests/FragDepth_test.cpp', '<(angle_path)/src/tests/compiler_tests/FragDepth_test.cpp',
'<(angle_path)/src/tests/compiler_tests/GLSLCompatibilityOutput_test.cpp', '<(angle_path)/src/tests/compiler_tests/GLSLCompatibilityOutput_test.cpp',
'<(angle_path)/src/tests/compiler_tests/InitOutputVariables_test.cpp',
'<(angle_path)/src/tests/compiler_tests/IntermNode_test.cpp', '<(angle_path)/src/tests/compiler_tests/IntermNode_test.cpp',
'<(angle_path)/src/tests/compiler_tests/NV_draw_buffers_test.cpp', '<(angle_path)/src/tests/compiler_tests/NV_draw_buffers_test.cpp',
'<(angle_path)/src/tests/compiler_tests/Pack_Unpack_test.cpp', '<(angle_path)/src/tests/compiler_tests/Pack_Unpack_test.cpp',
......
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