Commit 72111915 by Zhenyao Mo Committed by Commit Bot

Initialize all output variables.

BUG=angleproject:1441 TEST=bots Change-Id: Ia4cf415d8346c3234bf0f548a178ee3ea8cd35c4 Reviewed-on: https://chromium-review.googlesource.com/362110Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarZhenyao Mo <zmo@chromium.org> Commit-Queue: Zhenyao Mo <zmo@chromium.org>
parent dacac90a
......@@ -48,7 +48,7 @@ typedef unsigned int GLenum;
// Version number for shader translation API.
// It is incremented every time the API changes.
#define ANGLE_SH_VERSION 149
#define ANGLE_SH_VERSION 150
typedef enum {
SH_GLES2_SPEC,
......@@ -184,10 +184,10 @@ typedef enum {
// independent of |a|'s value.
SH_UNFOLD_SHORT_CIRCUIT = 0x10000,
// This flag initializes varyings without static use in vertex shader
// at the beginning of main(), and has no effects in the fragment shader.
// It is intended as a workaround for drivers which incorrectly optimize
// out such varyings and cause a link failure.
// This flag initializes output variables to 0 at the beginning of main().
// It is to avoid undefined behaviors.
SH_INIT_OUTPUT_VARIABLES = 0x20000,
// TODO(zmo): obsolete, remove after ANGLE roll into Chromium.
SH_INIT_VARYINGS_WITHOUT_STATIC_USE = 0x20000,
// This flag scalarizes vec/ivec/bvec/mat constructor args.
......
......@@ -362,9 +362,10 @@ TIntermNode *TCompiler::compileTreeImpl(const char *const shaderStrings[],
infoSink.info << "too many uniforms";
}
}
if (success && shaderType == GL_VERTEX_SHADER &&
(compileOptions & SH_INIT_VARYINGS_WITHOUT_STATIC_USE))
initializeVaryingsWithoutStaticUse(root);
if (success && (compileOptions & SH_INIT_OUTPUT_VARIABLES))
{
initializeOutputVariables(root, shaderType);
}
}
if (success && (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS))
......@@ -810,37 +811,32 @@ bool TCompiler::enforcePackingRestrictions()
void TCompiler::initializeGLPosition(TIntermNode* root)
{
InitializeVariables::InitVariableInfoList variables;
InitializeVariables::InitVariableInfo var(
"gl_Position", TType(EbtFloat, EbpUndefined, EvqPosition, 4));
variables.push_back(var);
InitializeVariables initializer(variables);
root->traverse(&initializer);
InitVariableList list;
sh::ShaderVariable var(GL_FLOAT_VEC4, 0);
var.name = "gl_Position";
list.push_back(var);
InitializeVariables(root, list);
}
void TCompiler::initializeVaryingsWithoutStaticUse(TIntermNode* root)
void TCompiler::initializeOutputVariables(TIntermNode *root, sh::GLenum shaderType)
{
InitializeVariables::InitVariableInfoList variables;
for (size_t ii = 0; ii < varyings.size(); ++ii)
InitVariableList list;
if (shaderType == GL_VERTEX_SHADER)
{
const sh::Varying& varying = varyings[ii];
if (varying.staticUse)
continue;
unsigned char primarySize = static_cast<unsigned char>(gl::VariableColumnCount(varying.type));
unsigned char secondarySize = static_cast<unsigned char>(gl::VariableRowCount(varying.type));
TType type(EbtFloat, EbpUndefined, EvqVaryingOut, primarySize, secondarySize, varying.isArray());
TString name = varying.name.c_str();
if (varying.isArray())
for (auto var : varyings)
{
type.setArraySize(varying.arraySize);
name = name.substr(0, name.find_first_of('['));
sh::ExpandVariable(var, var.name, var.mappedName, false, &list);
}
}
else
{
ASSERT(shaderType == GL_FRAGMENT_SHADER);
for (auto var : outputVariables)
{
list.push_back(var);
}
InitializeVariables::InitVariableInfo var(name, type);
variables.push_back(var);
}
InitializeVariables initializer(variables);
root->traverse(&initializer);
InitializeVariables(root, list);
}
const TExtensionBehavior& TCompiler::getExtensionBehavior() const
......
......@@ -130,11 +130,9 @@ class TCompiler : public TShHandleBase
// Returns true if, after applying the packing rules in the GLSL 1.017 spec
// Appendix A, section 7, the shader does not use too many uniforms.
bool enforcePackingRestrictions();
// Insert statements to initialize varyings without static use in the beginning
// of main(). It is to work around a Mac driver where such varyings in a vertex
// shader may be optimized out incorrectly at compile time, causing a link failure.
// This function should only be applied to vertex shaders.
void initializeVaryingsWithoutStaticUse(TIntermNode* root);
// Insert statements to initialize output variables in the beginning of main().
// This is to avoid undefined behaviors.
void initializeOutputVariables(TIntermNode *root, sh::GLenum shaderType);
// Insert gl_Position = vec4(0,0,0,0) to the beginning of main().
// It is to work around a Linux driver bug where missing this causes compile failure
// while spec says it is allowed.
......
......@@ -6,23 +6,40 @@
#include "compiler/translator/InitializeVariables.h"
#include "angle_gl.h"
#include "common/debug.h"
#include "compiler/translator/IntermNode.h"
#include "compiler/translator/util.h"
namespace
{
TIntermConstantUnion *constructFloatConstUnionNode(const TType &type)
TIntermConstantUnion *constructConstUnionNode(const TType &type)
{
TType myType = type;
unsigned char size = static_cast<unsigned char>(myType.getNominalSize());
if (myType.isMatrix())
size *= size;
myType.clearArrayness();
myType.setQualifier(EvqConst);
size_t size = myType.getObjectSize();
TConstantUnion *u = new TConstantUnion[size];
for (int ii = 0; ii < size; ++ii)
for (size_t ii = 0; ii < size; ++ii)
{
switch (type.getBasicType())
{
case EbtFloat:
u[ii].setFConst(0.0f);
break;
case EbtInt:
u[ii].setIConst(0);
break;
case EbtUInt:
u[ii].setUConst(0u);
break;
default:
UNREACHABLE();
return nullptr;
}
}
myType.clearArrayness();
myType.setQualifier(EvqConst);
TIntermConstantUnion *node = new TIntermConstantUnion(u, myType);
return node;
}
......@@ -37,9 +54,33 @@ TIntermConstantUnion *constructIndexNode(int index)
return node;
}
} // namespace anonymous
class VariableInitializer : public TIntermTraverser
{
public:
VariableInitializer(const InitVariableList &vars)
: TIntermTraverser(true, false, false), mVariables(vars), mCodeInserted(false)
{
}
protected:
bool visitBinary(Visit, TIntermBinary *node) override { return false; }
bool visitUnary(Visit, TIntermUnary *node) override { return false; }
bool visitSelection(Visit, TIntermSelection *node) override { return false; }
bool visitLoop(Visit, TIntermLoop *node) override { return false; }
bool visitBranch(Visit, TIntermBranch *node) override { return false; }
bool visitAggregate(Visit visit, TIntermAggregate *node) override;
private:
void insertInitCode(TIntermSequence *sequence);
const InitVariableList &mVariables;
bool mCodeInserted;
};
bool InitializeVariables::visitAggregate(Visit visit, TIntermAggregate *node)
// VariableInitializer implementation.
bool VariableInitializer::visitAggregate(Visit visit, TIntermAggregate *node)
{
bool visitChildren = !mCodeInserted;
switch (node->getOp())
......@@ -77,28 +118,33 @@ bool InitializeVariables::visitAggregate(Visit visit, TIntermAggregate *node)
return visitChildren;
}
void InitializeVariables::insertInitCode(TIntermSequence *sequence)
void VariableInitializer::insertInitCode(TIntermSequence *sequence)
{
for (size_t ii = 0; ii < mVariables.size(); ++ii)
{
const InitVariableInfo &varInfo = mVariables[ii];
if (varInfo.type.isArray())
const sh::ShaderVariable &var = mVariables[ii];
ASSERT(!var.isStruct());
TType type = sh::ConvertShaderVariableTypeToTType(var.type);
TString name = TString(var.name.c_str());
if (var.isArray())
{
for (int index = varInfo.type.getArraySize() - 1; index >= 0; --index)
size_t pos = name.find_last_of('[');
if (pos != TString::npos)
name = name.substr(0, pos);
for (int index = static_cast<int>(var.arraySize) - 1; index >= 0; --index)
{
TIntermBinary *assign = new TIntermBinary(EOpAssign);
sequence->insert(sequence->begin(), assign);
TIntermBinary *indexDirect = new TIntermBinary(EOpIndexDirect);
TIntermSymbol *symbol = new TIntermSymbol(0, varInfo.name, varInfo.type);
TIntermSymbol *symbol = new TIntermSymbol(0, name, type);
indexDirect->setLeft(symbol);
TIntermConstantUnion *indexNode = constructIndexNode(index);
indexDirect->setRight(indexNode);
assign->setLeft(indexDirect);
TIntermConstantUnion *zeroConst = constructFloatConstUnionNode(varInfo.type);
TIntermConstantUnion *zeroConst = constructConstUnionNode(type);
assign->setRight(zeroConst);
}
}
......@@ -106,12 +152,19 @@ void InitializeVariables::insertInitCode(TIntermSequence *sequence)
{
TIntermBinary *assign = new TIntermBinary(EOpAssign);
sequence->insert(sequence->begin(), assign);
TIntermSymbol *symbol = new TIntermSymbol(0, varInfo.name, varInfo.type);
TIntermSymbol *symbol = new TIntermSymbol(0, name, type);
assign->setLeft(symbol);
TIntermConstantUnion *zeroConst = constructFloatConstUnionNode(varInfo.type);
TIntermConstantUnion *zeroConst = constructConstUnionNode(type);
assign->setRight(zeroConst);
}
}
}
} // namespace anonymous
void InitializeVariables(TIntermNode *root, const InitVariableList &vars)
{
VariableInitializer initializer(vars);
root->traverse(&initializer);
}
......@@ -7,45 +7,12 @@
#ifndef COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_
#define COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_
#include "compiler/translator/IntermNode.h"
#include <GLSLANG/ShaderLang.h>
class InitializeVariables : public TIntermTraverser
{
public:
struct InitVariableInfo
{
TString name;
TType type;
class TIntermNode;
InitVariableInfo(const TString &_name, const TType &_type)
: name(_name),
type(_type)
{
}
};
typedef TVector<InitVariableInfo> InitVariableInfoList;
typedef std::vector<sh::ShaderVariable> InitVariableList;
InitializeVariables(const InitVariableInfoList &vars)
: TIntermTraverser(true, false, false),
mVariables(vars),
mCodeInserted(false)
{
}
protected:
bool visitBinary(Visit, TIntermBinary *node) override { return false; }
bool visitUnary(Visit, TIntermUnary *node) override { return false; }
bool visitSelection(Visit, TIntermSelection *node) override { return false; }
bool visitLoop(Visit, TIntermLoop *node) override { return false; }
bool visitBranch(Visit, TIntermBranch *node) override { return false; }
bool visitAggregate(Visit visit, TIntermAggregate *node) override;
private:
void insertInitCode(TIntermSequence *sequence);
InitVariableInfoList mVariables;
bool mCodeInserted;
};
void InitializeVariables(TIntermNode *root, const InitVariableList &vars);
#endif // COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_
......@@ -278,6 +278,58 @@ InterpolationType GetInterpolationType(TQualifier qualifier)
}
}
TType ConvertShaderVariableTypeToTType(sh::GLenum type)
{
switch (type)
{
case GL_FLOAT:
return TType(EbtFloat);
case GL_FLOAT_VEC2:
return TType(EbtFloat, 2);
case GL_FLOAT_VEC3:
return TType(EbtFloat, 3);
case GL_FLOAT_VEC4:
return TType(EbtFloat, 4);
case GL_FLOAT_MAT2:
return TType(EbtFloat, 2, 2);
case GL_FLOAT_MAT3:
return TType(EbtFloat, 3, 3);
case GL_FLOAT_MAT4:
return TType(EbtFloat, 4, 4);
case GL_FLOAT_MAT2x3:
return TType(EbtFloat, 2, 3);
case GL_FLOAT_MAT2x4:
return TType(EbtFloat, 2, 4);
case GL_FLOAT_MAT3x2:
return TType(EbtFloat, 3, 2);
case GL_FLOAT_MAT3x4:
return TType(EbtFloat, 3, 4);
case GL_FLOAT_MAT4x2:
return TType(EbtFloat, 4, 2);
case GL_FLOAT_MAT4x3:
return TType(EbtFloat, 4, 3);
case GL_INT:
return TType(EbtInt);
case GL_INT_VEC2:
return TType(EbtInt, 2);
case GL_INT_VEC3:
return TType(EbtInt, 3);
case GL_INT_VEC4:
return TType(EbtInt, 4);
case GL_UNSIGNED_INT:
return TType(EbtUInt);
case GL_UNSIGNED_INT_VEC2:
return TType(EbtUInt, 2);
case GL_UNSIGNED_INT_VEC3:
return TType(EbtUInt, 3);
case GL_UNSIGNED_INT_VEC4:
return TType(EbtUInt, 4);
default:
UNREACHABLE();
return TType();
}
}
GetVariableTraverser::GetVariableTraverser(const TSymbolTable &symbolTable)
: mSymbolTable(symbolTable)
{
......
......@@ -36,6 +36,8 @@ bool IsVaryingOut(TQualifier qualifier);
bool IsVarying(TQualifier qualifier);
InterpolationType GetInterpolationType(TQualifier qualifier);
TString ArrayString(const TType &type);
// Handles only basic output variable types.
TType ConvertShaderVariableTypeToTType(sh::GLenum type);
class GetVariableTraverser : angle::NonCopyable
{
......
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