Commit daeac238 by Shahbaz Youssefi Committed by Commit Bot

Translator: Ensure structs and blocks are uniquely defined

A new AST validation is added to ensure that the same TStructure or TInterfaceBlock is not redundantly defined. This helps with SPIR-V generation by allowing the id to be used as key in a hash map that looks up the corresponding SPIR-V type id. A bug is fixed where the Vulkan driver uniform declaration created two identical declarations for ANGLEDepthRangeParams. A number of other bugs are also fixed in this change, where if a variable declaration is eliminated (for example due to constant folding, or inactive interface variable removal) and it contained a struct specifier, the struct declaration was also removed. OutputGLSLBase had a hack where structs were declared on first encounter, which was incorrect as the scope of the declaration could change. Those bugs are fixed and this hack is removed. Bug: angleproject:2733 Bug: angleproject:4889 Bug: angleproject:5936 Change-Id: I8e13748c0bf552ae8b052249282769a1f0775603 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2881942Reviewed-by: 's avatarCharlie Lao <cclao@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent 84d22197
...@@ -395,8 +395,8 @@ void TOutputGLSLBase::writeVariableType(const TType &type, ...@@ -395,8 +395,8 @@ void TOutputGLSLBase::writeVariableType(const TType &type,
out << getMemoryQualifiers(type); out << getMemoryQualifiers(type);
} }
// Declare the struct if we have not done so already. // Declare the struct.
if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct())) if (type.isStructSpecifier())
{ {
const TStructure *structure = type.getStruct(); const TStructure *structure = type.getStruct();
...@@ -1279,17 +1279,6 @@ ImmutableString TOutputGLSLBase::hashFunctionNameIfNeeded(const TFunction *func) ...@@ -1279,17 +1279,6 @@ ImmutableString TOutputGLSLBase::hashFunctionNameIfNeeded(const TFunction *func)
} }
} }
bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
{
ASSERT(structure);
if (structure->symbolType() == SymbolType::Empty)
{
return false;
}
return (mDeclaredStructs.count(structure->uniqueId().get()) > 0);
}
void TOutputGLSLBase::declareStruct(const TStructure *structure) void TOutputGLSLBase::declareStruct(const TStructure *structure)
{ {
TInfoSinkBase &out = objSink(); TInfoSinkBase &out = objSink();
...@@ -1313,11 +1302,6 @@ void TOutputGLSLBase::declareStruct(const TStructure *structure) ...@@ -1313,11 +1302,6 @@ void TOutputGLSLBase::declareStruct(const TStructure *structure)
out << ";\n"; out << ";\n";
} }
out << "}"; out << "}";
if (structure->symbolType() != SymbolType::Empty)
{
mDeclaredStructs.insert(structure->uniqueId().get());
}
} }
void TOutputGLSLBase::declareInterfaceBlockLayout(const TType &type) void TOutputGLSLBase::declareInterfaceBlockLayout(const TType &type)
......
...@@ -89,7 +89,6 @@ class TOutputGLSLBase : public TIntermTraverser ...@@ -89,7 +89,6 @@ class TOutputGLSLBase : public TIntermTraverser
void declareStruct(const TStructure *structure); void declareStruct(const TStructure *structure);
void writeQualifier(TQualifier qualifier, const TType &type, const TSymbol *symbol); void writeQualifier(TQualifier qualifier, const TType &type, const TSymbol *symbol);
bool structDeclared(const TStructure *structure) const;
const char *mapQualifierToString(TQualifier qualifier); const char *mapQualifierToString(TQualifier qualifier);
...@@ -104,9 +103,6 @@ class TOutputGLSLBase : public TIntermTraverser ...@@ -104,9 +103,6 @@ class TOutputGLSLBase : public TIntermTraverser
TInfoSinkBase &mObjSink; TInfoSinkBase &mObjSink;
bool mDeclaringVariable; bool mDeclaringVariable;
// This set contains all the ids of the structs from every scope.
std::set<int> mDeclaredStructs;
ShArrayIndexClampingStrategy mClampingStrategy; ShArrayIndexClampingStrategy mClampingStrategy;
// name hashing. // name hashing.
......
...@@ -174,15 +174,6 @@ void TOutputVulkanGLSL::writeVariableType(const TType &type, ...@@ -174,15 +174,6 @@ void TOutputVulkanGLSL::writeVariableType(const TType &type,
TOutputGLSL::writeVariableType(overrideType, symbol, isFunctionArgument); TOutputGLSL::writeVariableType(overrideType, symbol, isFunctionArgument);
} }
void TOutputVulkanGLSL::writeStructType(const TStructure *structure)
{
if (!structDeclared(structure))
{
declareStruct(structure);
objSink() << ";\n";
}
}
bool TOutputVulkanGLSL::writeVariablePrecision(TPrecision precision) bool TOutputVulkanGLSL::writeVariablePrecision(TPrecision precision)
{ {
if ((precision == EbpUndefined) || !mEnablePrecision) if ((precision == EbpUndefined) || !mEnablePrecision)
......
...@@ -32,8 +32,6 @@ class TOutputVulkanGLSL : public TOutputGLSL ...@@ -32,8 +32,6 @@ class TOutputVulkanGLSL : public TOutputGLSL
bool enablePrecision, bool enablePrecision,
ShCompileOptions compileOptions); ShCompileOptions compileOptions);
void writeStructType(const TStructure *structure);
uint32_t nextUnusedBinding() { return mNextUnusedBinding++; } uint32_t nextUnusedBinding() { return mNextUnusedBinding++; }
uint32_t nextUnusedInputLocation(uint32_t consumedCount) uint32_t nextUnusedInputLocation(uint32_t consumedCount)
{ {
......
...@@ -2997,6 +2997,15 @@ TIntermDeclaration *TParseContext::parseSingleInitDeclaration(const TPublicType ...@@ -2997,6 +2997,15 @@ TIntermDeclaration *TParseContext::parseSingleInitDeclaration(const TPublicType
{ {
declaration->appendDeclarator(initNode); declaration->appendDeclarator(initNode);
} }
else if (publicType.isStructSpecifier())
{
// The initialization got constant folded. If it's a struct, declare the struct anyway.
TVariable *emptyVariable =
new TVariable(&symbolTable, kEmptyImmutableString, type, SymbolType::Empty);
TIntermSymbol *symbol = new TIntermSymbol(emptyVariable);
symbol->setLine(publicType.getLine());
declaration->appendDeclarator(symbol);
}
} }
return declaration; return declaration;
} }
......
...@@ -116,7 +116,7 @@ ANGLE_NO_DISCARD bool InitializeUnusedOutputs(TIntermBlock *root, ...@@ -116,7 +116,7 @@ ANGLE_NO_DISCARD bool InitializeUnusedOutputs(TIntermBlock *root,
} // anonymous namespace } // anonymous namespace
// class DriverUniformMetal // class DriverUniformMetal
TFieldList *DriverUniformMetal::createUniformFields(TSymbolTable *symbolTable) const TFieldList *DriverUniformMetal::createUniformFields(TSymbolTable *symbolTable)
{ {
TFieldList *driverFieldList = DriverUniform::createUniformFields(symbolTable); TFieldList *driverFieldList = DriverUniform::createUniformFields(symbolTable);
......
...@@ -48,7 +48,7 @@ class DriverUniformMetal : public DriverUniform ...@@ -48,7 +48,7 @@ class DriverUniformMetal : public DriverUniform
TIntermBinary *getCoverageMaskFieldRef() const; TIntermBinary *getCoverageMaskFieldRef() const;
protected: protected:
TFieldList *createUniformFields(TSymbolTable *symbolTable) const override; TFieldList *createUniformFields(TSymbolTable *symbolTable) override;
}; };
class TranslatorMetal : public TranslatorVulkan class TranslatorMetal : public TranslatorVulkan
......
...@@ -814,8 +814,8 @@ bool TranslatorVulkan::translateImpl(TInfoSinkBase &sink, ...@@ -814,8 +814,8 @@ bool TranslatorVulkan::translateImpl(TInfoSinkBase &sink,
// inactive samplers is not yet supported. Note also that currently, CollectVariables marks // inactive samplers is not yet supported. Note also that currently, CollectVariables marks
// every field of an active uniform that's of struct type as active, i.e. no extracted sampler // every field of an active uniform that's of struct type as active, i.e. no extracted sampler
// is inactive. // is inactive.
if (!RemoveInactiveInterfaceVariables(this, root, getAttributes(), getInputVaryings(), if (!RemoveInactiveInterfaceVariables(this, root, &getSymbolTable(), getAttributes(),
getOutputVariables(), getUniforms(), getInputVaryings(), getOutputVariables(), getUniforms(),
getInterfaceBlocks())) getInterfaceBlocks()))
{ {
return false; return false;
......
...@@ -42,9 +42,11 @@ struct ValidateASTOptions ...@@ -42,9 +42,11 @@ struct ValidateASTOptions
// Check that there is only one TFunction with each function name referenced in the nodes (no // Check that there is only one TFunction with each function name referenced in the nodes (no
// two TFunctions with the same name, taking internal/non-internal namespaces into account). // two TFunctions with the same name, taking internal/non-internal namespaces into account).
bool validateUniqueFunctions = true; // TODO bool validateUniqueFunctions = true; // TODO
// Check that references to user-defined structs are matched with the corresponding struct // Check that references to structs are matched with the corresponding struct declaration. This
// is only done for references to structs inside other struct or interface blocks declarations,
// as validateVariableReferences already ensures other references to the struct match the
// declaration. // declaration.
bool validateStructUsage = true; // TODO bool validateStructUsage = true;
// Check that expression nodes have the correct type considering their operand(s). // Check that expression nodes have the correct type considering their operand(s).
bool validateExpressionTypes = true; // TODO bool validateExpressionTypes = true; // TODO
// If SeparateDeclarations has been run, check for the absence of multi declarations as well. // If SeparateDeclarations has been run, check for the absence of multi declarations as well.
......
...@@ -24,29 +24,13 @@ class TPrecisionTraverser : public TIntermTraverser ...@@ -24,29 +24,13 @@ class TPrecisionTraverser : public TIntermTraverser
protected: protected:
bool visitDeclaration(Visit visit, TIntermDeclaration *node) override; bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
bool structDeclared(const TStructure *structure) const;
void overwriteVariablePrecision(TType *type) const; void overwriteVariablePrecision(TType *type) const;
private:
// This set contains all the ids of the structs from every scope.
std::set<int> mDeclaredStructs;
}; };
TPrecisionTraverser::TPrecisionTraverser(TSymbolTable *symbolTable) TPrecisionTraverser::TPrecisionTraverser(TSymbolTable *symbolTable)
: TIntermTraverser(true, true, true, symbolTable) : TIntermTraverser(true, true, true, symbolTable)
{} {}
bool TPrecisionTraverser::structDeclared(const TStructure *structure) const
{
ASSERT(structure);
if (structure->symbolType() == SymbolType::Empty)
{
return false;
}
return (mDeclaredStructs.count(structure->uniqueId().get()) > 0);
}
void TPrecisionTraverser::overwriteVariablePrecision(TType *type) const void TPrecisionTraverser::overwriteVariablePrecision(TType *type) const
{ {
if (type->getPrecision() == EbpHigh) if (type->getPrecision() == EbpHigh)
...@@ -71,8 +55,8 @@ bool TPrecisionTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node ...@@ -71,8 +55,8 @@ bool TPrecisionTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node
return true; return true;
} }
// Visit the struct if we have not done so already. // Visit the struct.
if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct())) if (type.isStructSpecifier())
{ {
const TStructure *structure = type.getStruct(); const TStructure *structure = type.getStruct();
const TFieldList &fields = structure->fields(); const TFieldList &fields = structure->fields();
...@@ -82,7 +66,6 @@ bool TPrecisionTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node ...@@ -82,7 +66,6 @@ bool TPrecisionTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node
const TType *fieldType = field->type(); const TType *fieldType = field->type();
overwriteVariablePrecision((TType *)fieldType); overwriteVariablePrecision((TType *)fieldType);
} }
mDeclaredStructs.insert(structure->uniqueId().get());
} }
else if (type.getBasicType() == EbtInterfaceBlock) else if (type.getBasicType() == EbtInterfaceBlock)
{ {
......
...@@ -24,6 +24,7 @@ class RemoveInactiveInterfaceVariablesTraverser : public TIntermTraverser ...@@ -24,6 +24,7 @@ class RemoveInactiveInterfaceVariablesTraverser : public TIntermTraverser
{ {
public: public:
RemoveInactiveInterfaceVariablesTraverser( RemoveInactiveInterfaceVariablesTraverser(
TSymbolTable *symbolTable,
const std::vector<sh::ShaderVariable> &attributes, const std::vector<sh::ShaderVariable> &attributes,
const std::vector<sh::ShaderVariable> &inputVaryings, const std::vector<sh::ShaderVariable> &inputVaryings,
const std::vector<sh::ShaderVariable> &outputVariables, const std::vector<sh::ShaderVariable> &outputVariables,
...@@ -41,12 +42,13 @@ class RemoveInactiveInterfaceVariablesTraverser : public TIntermTraverser ...@@ -41,12 +42,13 @@ class RemoveInactiveInterfaceVariablesTraverser : public TIntermTraverser
}; };
RemoveInactiveInterfaceVariablesTraverser::RemoveInactiveInterfaceVariablesTraverser( RemoveInactiveInterfaceVariablesTraverser::RemoveInactiveInterfaceVariablesTraverser(
TSymbolTable *symbolTable,
const std::vector<sh::ShaderVariable> &attributes, const std::vector<sh::ShaderVariable> &attributes,
const std::vector<sh::ShaderVariable> &inputVaryings, const std::vector<sh::ShaderVariable> &inputVaryings,
const std::vector<sh::ShaderVariable> &outputVariables, const std::vector<sh::ShaderVariable> &outputVariables,
const std::vector<sh::ShaderVariable> &uniforms, const std::vector<sh::ShaderVariable> &uniforms,
const std::vector<sh::InterfaceBlock> &interfaceBlocks) const std::vector<sh::InterfaceBlock> &interfaceBlocks)
: TIntermTraverser(true, false, false), : TIntermTraverser(true, false, false, symbolTable),
mAttributes(attributes), mAttributes(attributes),
mInputVaryings(inputVaryings), mInputVaryings(inputVaryings),
mOutputVariables(outputVariables), mOutputVariables(outputVariables),
...@@ -128,9 +130,21 @@ bool RemoveInactiveInterfaceVariablesTraverser::visitDeclaration(Visit visit, ...@@ -128,9 +130,21 @@ bool RemoveInactiveInterfaceVariablesTraverser::visitDeclaration(Visit visit,
if (removeDeclaration) if (removeDeclaration)
{ {
TIntermSequence emptySequence; TIntermSequence replacement;
// If the declaration was of a struct, keep the struct declaration itself.
if (type.isStructSpecifier())
{
TType *structSpecifierType = new TType(type.getStruct(), true);
TVariable *emptyVariable = new TVariable(mSymbolTable, kEmptyImmutableString,
structSpecifierType, SymbolType::Empty);
TIntermDeclaration *declaration = new TIntermDeclaration();
declaration->appendDeclarator(new TIntermSymbol(emptyVariable));
replacement.push_back(declaration);
}
mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), node, mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), node,
std::move(emptySequence)); std::move(replacement));
} }
return false; return false;
...@@ -140,14 +154,15 @@ bool RemoveInactiveInterfaceVariablesTraverser::visitDeclaration(Visit visit, ...@@ -140,14 +154,15 @@ bool RemoveInactiveInterfaceVariablesTraverser::visitDeclaration(Visit visit,
bool RemoveInactiveInterfaceVariables(TCompiler *compiler, bool RemoveInactiveInterfaceVariables(TCompiler *compiler,
TIntermBlock *root, TIntermBlock *root,
TSymbolTable *symbolTable,
const std::vector<sh::ShaderVariable> &attributes, const std::vector<sh::ShaderVariable> &attributes,
const std::vector<sh::ShaderVariable> &inputVaryings, const std::vector<sh::ShaderVariable> &inputVaryings,
const std::vector<sh::ShaderVariable> &outputVariables, const std::vector<sh::ShaderVariable> &outputVariables,
const std::vector<sh::ShaderVariable> &uniforms, const std::vector<sh::ShaderVariable> &uniforms,
const std::vector<sh::InterfaceBlock> &interfaceBlocks) const std::vector<sh::InterfaceBlock> &interfaceBlocks)
{ {
RemoveInactiveInterfaceVariablesTraverser traverser(attributes, inputVaryings, outputVariables, RemoveInactiveInterfaceVariablesTraverser traverser(symbolTable, attributes, inputVaryings,
uniforms, interfaceBlocks); outputVariables, uniforms, interfaceBlocks);
root->traverse(&traverser); root->traverse(&traverser);
return traverser.updateTree(compiler, root); return traverser.updateTree(compiler, root);
} }
......
...@@ -29,6 +29,7 @@ class TSymbolTable; ...@@ -29,6 +29,7 @@ class TSymbolTable;
ANGLE_NO_DISCARD bool RemoveInactiveInterfaceVariables( ANGLE_NO_DISCARD bool RemoveInactiveInterfaceVariables(
TCompiler *compiler, TCompiler *compiler,
TIntermBlock *root, TIntermBlock *root,
TSymbolTable *symbolTable,
const std::vector<sh::ShaderVariable> &attributes, const std::vector<sh::ShaderVariable> &attributes,
const std::vector<sh::ShaderVariable> &inputVaryings, const std::vector<sh::ShaderVariable> &inputVaryings,
const std::vector<sh::ShaderVariable> &outputVariables, const std::vector<sh::ShaderVariable> &outputVariables,
......
...@@ -71,7 +71,7 @@ bool DriverUniform::addComputeDriverUniformsToShader(TIntermBlock *root, TSymbol ...@@ -71,7 +71,7 @@ bool DriverUniform::addComputeDriverUniformsToShader(TIntermBlock *root, TSymbol
return mDriverUniforms != nullptr; return mDriverUniforms != nullptr;
} }
TFieldList *DriverUniform::createUniformFields(TSymbolTable *symbolTable) const TFieldList *DriverUniform::createUniformFields(TSymbolTable *symbolTable)
{ {
constexpr size_t kNumGraphicsDriverUniforms = 8; constexpr size_t kNumGraphicsDriverUniforms = 8;
constexpr std::array<const char *, kNumGraphicsDriverUniforms> kGraphicsDriverUniformNames = { constexpr std::array<const char *, kNumGraphicsDriverUniforms> kGraphicsDriverUniformNames = {
...@@ -104,9 +104,15 @@ TFieldList *DriverUniform::createUniformFields(TSymbolTable *symbolTable) const ...@@ -104,9 +104,15 @@ TFieldList *DriverUniform::createUniformFields(TSymbolTable *symbolTable) const
return driverFieldList; return driverFieldList;
} }
TType *DriverUniform::createEmulatedDepthRangeType(TSymbolTable *symbolTable) const TType *DriverUniform::createEmulatedDepthRangeType(TSymbolTable *symbolTable)
{ {
// Init the depth range type. // If already defined, return it immediately.
if (mEmulatedDepthRangeType != nullptr)
{
return mEmulatedDepthRangeType;
}
// Create the depth range type.
TFieldList *depthRangeParamsFields = new TFieldList(); TFieldList *depthRangeParamsFields = new TFieldList();
depthRangeParamsFields->push_back(new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1, 1), depthRangeParamsFields->push_back(new TField(new TType(EbtFloat, EbpHigh, EvqGlobal, 1, 1),
ImmutableString("near"), TSourceLoc(), ImmutableString("near"), TSourceLoc(),
...@@ -125,9 +131,11 @@ TType *DriverUniform::createEmulatedDepthRangeType(TSymbolTable *symbolTable) co ...@@ -125,9 +131,11 @@ TType *DriverUniform::createEmulatedDepthRangeType(TSymbolTable *symbolTable) co
TStructure *emulatedDepthRangeParams = new TStructure( TStructure *emulatedDepthRangeParams = new TStructure(
symbolTable, kEmulatedDepthRangeParams, depthRangeParamsFields, SymbolType::AngleInternal); symbolTable, kEmulatedDepthRangeParams, depthRangeParamsFields, SymbolType::AngleInternal);
TType *emulatedDepthRangeType = new TType(emulatedDepthRangeParams, false); mEmulatedDepthRangeType = new TType(emulatedDepthRangeParams, false);
return emulatedDepthRangeType; // Note: this should really return a const TType *, but one of its uses is with TField who takes
// a non-const TType. See comment on that class.
return mEmulatedDepthRangeType;
} }
// The Add*DriverUniformsToShader operation adds an internal uniform block to a shader. The driver // The Add*DriverUniformsToShader operation adds an internal uniform block to a shader. The driver
...@@ -139,11 +147,13 @@ bool DriverUniform::addGraphicsDriverUniformsToShader(TIntermBlock *root, TSymbo ...@@ -139,11 +147,13 @@ bool DriverUniform::addGraphicsDriverUniformsToShader(TIntermBlock *root, TSymbo
{ {
ASSERT(!mDriverUniforms); ASSERT(!mDriverUniforms);
TType *emulatedDepthRangeType = createEmulatedDepthRangeType(symbolTable); // Declare the depth range struct type.
// Declare a global depth range variable. TType *emulatedDepthRangeType = createEmulatedDepthRangeType(symbolTable);
TType *emulatedDepthRangeDeclType = new TType(emulatedDepthRangeType->getStruct(), true);
TVariable *depthRangeVar = TVariable *depthRangeVar =
new TVariable(symbolTable->nextUniqueId(), kEmptyImmutableString, SymbolType::Empty, new TVariable(symbolTable->nextUniqueId(), kEmptyImmutableString, SymbolType::Empty,
TExtension::UNDEFINED, emulatedDepthRangeType); TExtension::UNDEFINED, emulatedDepthRangeDeclType);
DeclareGlobalVariable(root, depthRangeVar); DeclareGlobalVariable(root, depthRangeVar);
...@@ -220,7 +230,7 @@ TIntermBinary *DriverUniform::getNumSamplesRef() const ...@@ -220,7 +230,7 @@ TIntermBinary *DriverUniform::getNumSamplesRef() const
// //
// Class DriverUniformExtended // Class DriverUniformExtended
// //
TFieldList *DriverUniformExtended::createUniformFields(TSymbolTable *symbolTable) const TFieldList *DriverUniformExtended::createUniformFields(TSymbolTable *symbolTable)
{ {
TFieldList *driverFieldList = DriverUniform::createUniformFields(symbolTable); TFieldList *driverFieldList = DriverUniform::createUniformFields(symbolTable);
......
...@@ -26,7 +26,7 @@ class TIntermBinary; ...@@ -26,7 +26,7 @@ class TIntermBinary;
class DriverUniform class DriverUniform
{ {
public: public:
DriverUniform() : mDriverUniforms(nullptr) {} DriverUniform() : mDriverUniforms(nullptr), mEmulatedDepthRangeType(nullptr) {}
virtual ~DriverUniform() = default; virtual ~DriverUniform() = default;
bool addComputeDriverUniformsToShader(TIntermBlock *root, TSymbolTable *symbolTable); bool addComputeDriverUniformsToShader(TIntermBlock *root, TSymbolTable *symbolTable);
...@@ -50,10 +50,11 @@ class DriverUniform ...@@ -50,10 +50,11 @@ class DriverUniform
protected: protected:
TIntermBinary *createDriverUniformRef(const char *fieldName) const; TIntermBinary *createDriverUniformRef(const char *fieldName) const;
virtual TFieldList *createUniformFields(TSymbolTable *symbolTable) const; virtual TFieldList *createUniformFields(TSymbolTable *symbolTable);
TType *createEmulatedDepthRangeType(TSymbolTable *symbolTable) const; TType *createEmulatedDepthRangeType(TSymbolTable *symbolTable);
const TVariable *mDriverUniforms; const TVariable *mDriverUniforms;
TType *mEmulatedDepthRangeType;
}; };
class DriverUniformExtended : public DriverUniform class DriverUniformExtended : public DriverUniform
...@@ -69,7 +70,7 @@ class DriverUniformExtended : public DriverUniform ...@@ -69,7 +70,7 @@ class DriverUniformExtended : public DriverUniform
TIntermSwizzle *getNegFlipYRef() const override; TIntermSwizzle *getNegFlipYRef() const override;
protected: protected:
virtual TFieldList *createUniformFields(TSymbolTable *symbolTable) const override; virtual TFieldList *createUniformFields(TSymbolTable *symbolTable) override;
}; };
} // namespace sh } // namespace sh
......
...@@ -673,12 +673,6 @@ void main() ...@@ -673,12 +673,6 @@ void main()
TEST_P(GLSLTest, ScopedStructsOrderBug) TEST_P(GLSLTest, ScopedStructsOrderBug)
{ {
// TODO(geofflang): Find out why this doesn't compile on Apple OpenGL drivers
// (http://anglebug.com/1292)
// TODO(geofflang): Find out why this doesn't compile on AMD OpenGL drivers
// (http://anglebug.com/1291)
ANGLE_SKIP_TEST_IF(IsDesktopOpenGL() && (IsOSX() || !IsNVIDIA()));
constexpr char kFS[] = R"(precision mediump float; constexpr char kFS[] = R"(precision mediump float;
struct T struct T
...@@ -705,6 +699,132 @@ void main() ...@@ -705,6 +699,132 @@ void main()
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kFS); ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kFS);
} }
// Test that defining a struct together with an inactive uniform, then using it in a scope that has
// another struct with the same name declared works.
TEST_P(GLSLTest, ScopedStructsOrderBug2)
{
constexpr char kFS[] = R"(precision mediump float;
uniform struct T
{
float f;
} x;
void main()
{
T a;
struct T
{
float q;
};
T b;
gl_FragColor = vec4(1, 0, 0, 1);
gl_FragColor.a += a.f;
gl_FragColor.a += b.q;
})";
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kFS);
}
// Regression test based on WebGL's conformance/glsl/misc/empty-declaration.html
TEST_P(GLSLTest, StructEmptyDeclaratorBug)
{
constexpr char kVS[] = R"(
struct S {
float member;
}, a;
void main() {
a.member = 0.0;
gl_Position = vec4(a.member);
})";
constexpr char kFS[] = R"(precision mediump float;
precision mediump float;
void main()
{
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
})";
ANGLE_GL_PROGRAM(program, kVS, kFS);
}
// Regression test based on WebGL's conformance/ogles/GL/build/build_001_to_008.html
TEST_P(GLSLTest, StructConstantFoldingBug)
{
constexpr char kVS[] = R"(
void main()
{
const struct s2 {
int i;
vec3 v3;
bvec4 bv4;
} s22 = s2(8, vec3(9, 10, 11), bvec4(true, false, true, false));
struct s4 {
int ii;
vec4 v4;
};
const struct s1 {
s2 ss;
int i;
float f;
mat4 m;
s4 s44;
} s11 = s1(s22, 2, 4.0, mat4(5), s4(6, vec4(7, 8, 9, 10))) ;
const int field3 = s11.i * s11.ss.i; // constant folding (int * int)
const vec4 field4 = s11.s44.v4 * s11.s44.v4; // constant folding (vec4 * vec4)
// 49, 64, 81, 100
const vec4 v4 = vec4(s11.ss.v3.y, s11.m[3][3], field3, field4[2]); // 10.0, 5.0, 16.0, 81.0
gl_Position = v4;
})";
constexpr char kFS[] = R"(precision mediump float;
precision mediump float;
void main()
{
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
})";
ANGLE_GL_PROGRAM(program, kVS, kFS);
}
// Test that constant folding doesn't remove struct declaration.
TEST_P(GLSLTest, StructConstantFoldingBug2)
{
constexpr char kVS[] = R"(
uniform vec4 u;
void main()
{
const struct s2 {
int i;
vec3 v3;
bvec4 bv4;
} s22 = s2(8, vec3(9, 10, 11), bvec4(true, false, true, false));
s2 x;
x.v3 = u.xyz;
gl_Position = vec4(x.v3, float(s22.i));
})";
constexpr char kFS[] = R"(precision mediump float;
precision mediump float;
void main()
{
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
})";
ANGLE_GL_PROGRAM(program, kVS, kFS);
}
TEST_P(GLSLTest, ScopedStructsBug) TEST_P(GLSLTest, ScopedStructsBug)
{ {
constexpr char kFS[] = R"(precision mediump float; constexpr char kFS[] = R"(precision mediump float;
......
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