Commit ae4dbf32 by Olli Etuaho Committed by Commit Bot

Don't allocate name strings for empty symbols

This removes unnecessary memory allocations. BUG=angleproject:2267 TEST=angle_unittests Change-Id: Ide575ea19ab2f8e9fc93092490f1352efa6024a3 Reviewed-on: https://chromium-review.googlesource.com/817415 Commit-Queue: Olli Etuaho <oetuaho@nvidia.com> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent f2afccca
......@@ -91,7 +91,8 @@ ShaderVariable *FindVariableInInterfaceBlock(const TString &name,
std::vector<InterfaceBlock> *infoList)
{
ASSERT(interfaceBlock);
InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), infoList);
ASSERT(interfaceBlock->name());
InterfaceBlock *namedBlock = FindVariable(*interfaceBlock->name(), infoList);
ASSERT(namedBlock);
// Set static use on the parent interface block here
......@@ -569,7 +570,10 @@ void CollectVariablesTraverser::setCommonVariableProperties(const TType &type,
{
// Structures use a NONE type that isn't exposed outside ANGLE.
variableOut->type = GL_NONE;
variableOut->structName = structure->name().c_str();
if (structure->symbolType() != SymbolType::Empty)
{
variableOut->structName = structure->name()->c_str();
}
const TFieldList &fields = structure->fields();
......@@ -578,7 +582,7 @@ void CollectVariablesTraverser::setCommonVariableProperties(const TType &type,
// Regardless of the variable type (uniform, in/out etc.) its fields are always plain
// ShaderVariable objects.
ShaderVariable fieldVariable;
setCommonVariableProperties(*field->type(), TName(field->name()), &fieldVariable);
setCommonVariableProperties(*field->type(), TName(&field->name()), &fieldVariable);
variableOut->fields.push_back(fieldVariable);
}
}
......@@ -657,7 +661,7 @@ void CollectVariablesTraverser::recordInterfaceBlock(const TString &instanceName
const TInterfaceBlock *blockType = interfaceBlockType.getInterfaceBlock();
ASSERT(blockType);
interfaceBlock->name = blockType->name().c_str();
interfaceBlock->name = blockType->name()->c_str();
interfaceBlock->mappedName = getMappedName(TName(blockType->name()));
interfaceBlock->instanceName = instanceName.c_str();
ASSERT(!interfaceBlockType.isArrayOfArrays()); // Disallowed by GLSL ES 3.10 section 4.3.9
......@@ -679,7 +683,7 @@ void CollectVariablesTraverser::recordInterfaceBlock(const TString &instanceName
const TType &fieldType = *field->type();
InterfaceBlockField fieldVariable;
setCommonVariableProperties(fieldType, TName(field->name()), &fieldVariable);
setCommonVariableProperties(fieldType, TName(&field->name()), &fieldVariable);
fieldVariable.isRowMajorLayout =
(fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
interfaceBlock->fields.push_back(fieldVariable);
......@@ -825,7 +829,7 @@ bool CollectVariablesTraverser::visitBinary(Visit, TIntermBinary *binaryNode)
const TInterfaceBlock *interfaceBlock = blockNode->getType().getInterfaceBlock();
if (!namedBlock)
{
namedBlock = findNamedInterfaceBlock(interfaceBlock->name());
namedBlock = findNamedInterfaceBlock(*interfaceBlock->name());
}
ASSERT(namedBlock);
namedBlock->staticUse = true;
......
......@@ -431,7 +431,7 @@ TIntermAggregate *createInternalFunctionCallNode(const TType &type,
TString name,
TIntermSequence *arguments)
{
TName nameObj(name);
TName nameObj(&name);
nameObj.setInternal(true);
TIntermAggregate *callNode =
TIntermAggregate::Create(type, EOpCallInternalRawFunction, arguments);
......
......@@ -144,6 +144,10 @@ void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resu
} // namespace anonymous
TName::TName(const TString *name) : mName(name ? (*name) : ""), mIsInternal(false)
{
}
////////////////////////////////////////////////////////////////
//
// Member functions of the nodes used for building the tree.
......@@ -576,7 +580,7 @@ TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : T
void TFunctionSymbolInfo::setFromFunction(const TFunction &function)
{
setName(function.name());
setName(*function.name());
setId(TSymbolUniqueId(function));
}
......
......@@ -66,7 +66,7 @@ class TName
{
public:
POOL_ALLOCATOR_NEW_DELETE();
explicit TName(const TString &name) : mName(name), mIsInternal(false) {}
explicit TName(const TString *name);
TName() : mName(), mIsInternal(false) {}
TName(const TName &) = default;
TName &operator=(const TName &) = default;
......
......@@ -19,7 +19,7 @@ namespace
TName GetInternalFunctionName(const char *name)
{
TString nameStr(name);
TName nameObj(nameStr);
TName nameObj(&nameStr);
nameObj.setInternal(true);
return nameObj;
}
......
......@@ -585,7 +585,7 @@ bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
TString fieldName = field->name();
if (structure->symbolType() == SymbolType::UserDefined ||
structure->symbolType() == SymbolType::Empty)
fieldName = hashName(TName(fieldName));
fieldName = hashName(TName(&fieldName));
out << fieldName;
visitChildren = false;
......@@ -604,11 +604,11 @@ bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
ASSERT(interfaceBlock->symbolType() != SymbolType::Empty);
if (interfaceBlock->symbolType() == SymbolType::UserDefined)
{
fieldName = hashName(TName(fieldName));
fieldName = hashName(TName(&fieldName));
}
else
{
ASSERT(interfaceBlock->name() == "gl_PerVertex");
ASSERT(*interfaceBlock->name() == "gl_PerVertex");
}
out << fieldName;
......@@ -1177,7 +1177,7 @@ void TOutputGLSLBase::declareStruct(const TStructure *structure)
const TField *field = fields[i];
if (writeVariablePrecision(field->type()->getPrecision()))
out << " ";
out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
out << getTypeName(*field->type()) << " " << hashName(TName(&field->name()));
if (field->type()->isArray())
out << ArrayString(*field->type());
out << ";\n";
......@@ -1257,7 +1257,7 @@ void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBloc
if (writeVariablePrecision(field->type()->getPrecision()))
out << " ";
out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
out << getTypeName(*field->type()) << " " << hashName(TName(&field->name()));
if (field->type()->isArray())
out << ArrayString(*field->type());
out << ";\n";
......
......@@ -341,7 +341,7 @@ TString OutputHLSL::generateStructMapping(const std::vector<MappedStruct> &std14
{
TInterfaceBlock *interfaceBlock =
mappedStruct.blockDeclarator->getType().getInterfaceBlock();
const TString &interfaceBlockName = interfaceBlock->name();
const TString &interfaceBlockName = *interfaceBlock->name();
const TName &instanceName = mappedStruct.blockDeclarator->getName();
if (mReferencedUniformBlocks.count(interfaceBlockName) == 0)
{
......@@ -380,7 +380,7 @@ TString OutputHLSL::generateStructMapping(const std::vector<MappedStruct> &std14
TType *structType = mappedStruct.field->type();
mappedStructs +=
"static " + Decorate(structType->getStruct()->name()) + " " + mappedName;
"static " + Decorate(*structType->getStruct()->name()) + " " + mappedName;
if (structType->isArray())
{
......@@ -890,7 +890,7 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node)
if (interfaceBlock)
{
mReferencedUniformBlocks[interfaceBlock->name()] = node;
mReferencedUniformBlocks[*interfaceBlock->name()] = node;
}
else
{
......@@ -1238,7 +1238,7 @@ bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
{
TInterfaceBlock *interfaceBlock = leftType.getInterfaceBlock();
TIntermSymbol *instanceArraySymbol = node->getLeft()->getAsSymbolNode();
mReferencedUniformBlocks[interfaceBlock->name()] = instanceArraySymbol;
mReferencedUniformBlocks[*interfaceBlock->name()] = instanceArraySymbol;
const int arrayIndex = node->getRight()->getAsConstantUnion()->getIConst(0);
out << mUniformHLSL->UniformBlockInstanceString(
instanceArraySymbol->getSymbol(), arrayIndex);
......
......@@ -2445,7 +2445,7 @@ TIntermDeclaration *TParseContext::parseSingleDeclaration(
if (type.getBasicType() == EbtStruct)
{
TVariable *emptyVariable =
new TVariable(&symbolTable, NewPoolTString(""), type, SymbolType::Empty);
new TVariable(&symbolTable, nullptr, type, SymbolType::Empty);
symbol = new TIntermSymbol(emptyVariable);
}
else if (IsAtomicCounter(publicType.getBasicType()))
......@@ -3153,7 +3153,8 @@ TIntermFunctionPrototype *TParseContext::createPrototypeNodeFromFunction(
const TSourceLoc &location,
bool insertParametersToSymbolTable)
{
checkIsNotReserved(location, function.name());
ASSERT(function.name());
checkIsNotReserved(location, *function.name());
TIntermFunctionPrototype *prototype =
new TIntermFunctionPrototype(function.getReturnType(), TSymbolUniqueId(function));
......@@ -3200,7 +3201,7 @@ TIntermFunctionPrototype *TParseContext::createPrototypeNodeFromFunction(
// The parameter had no name or declaring the symbol failed - either way, add a nameless
// symbol.
TVariable *emptyVariable =
new TVariable(&symbolTable, NewPoolTString(""), *param.type, SymbolType::Empty);
new TVariable(&symbolTable, nullptr, *param.type, SymbolType::Empty);
symbol = new TIntermSymbol(emptyVariable);
}
symbol->setLine(location);
......@@ -3271,12 +3272,13 @@ void TParseContext::parseFunctionDefinitionHeader(const TSourceLoc &location,
{
ASSERT(function);
ASSERT(*function);
ASSERT((*function)->name());
const TSymbol *builtIn =
symbolTable.findBuiltIn((*function)->getMangledName(), getShaderVersion());
if (builtIn)
{
error(location, "built-in functions cannot be redefined", (*function)->name().c_str());
error(location, "built-in functions cannot be redefined", (*function)->name()->c_str());
}
else
{
......@@ -3298,7 +3300,7 @@ void TParseContext::parseFunctionDefinitionHeader(const TSourceLoc &location,
if ((*function)->isDefined())
{
error(location, "function already has a body", (*function)->name().c_str());
error(location, "function already has a body", (*function)->name()->c_str());
}
(*function)->setDefined();
......@@ -3325,6 +3327,8 @@ TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TF
TFunction *prevDec =
static_cast<TFunction *>(symbolTable.find(function->getMangledName(), getShaderVersion()));
ASSERT(function->name() != nullptr);
for (size_t i = 0u; i < function->getParamCount(); ++i)
{
auto &param = function->getParam(i);
......@@ -3332,17 +3336,17 @@ TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TF
{
// ESSL 3.00.6 section 12.10.
error(location, "Function parameter type cannot be a structure definition",
function->name().c_str());
function->name()->c_str());
}
}
if (getShaderVersion() >= 300 && symbolTable.hasUnmangledBuiltInForShaderVersion(
function->name().c_str(), getShaderVersion()))
function->name()->c_str(), getShaderVersion()))
{
// With ESSL 3.00 and above, names of built-in functions cannot be redeclared as functions.
// Therefore overloading or redefining builtin functions is an error.
error(location, "Name of a built-in function cannot be redeclared as function",
function->name().c_str());
function->name()->c_str());
}
else if (prevDec)
{
......@@ -3366,12 +3370,12 @@ TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TF
//
// Check for previously declared variables using the same name.
//
TSymbol *prevSym = symbolTable.find(function->name(), getShaderVersion());
TSymbol *prevSym = symbolTable.find(*function->name(), getShaderVersion());
if (prevSym)
{
if (!prevSym->isFunction())
{
error(location, "redefinition of a function", function->name().c_str());
error(location, "redefinition of a function", function->name()->c_str());
}
}
else
......@@ -3385,7 +3389,7 @@ TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TF
symbolTable.getOuterLevel()->insert(function);
// Raise error message if main function takes any parameters or return anything other than void
if (function->name() == "main")
if (*function->name() == "main")
{
if (function->getParamCount() > 0)
{
......@@ -3814,16 +3818,13 @@ TIntermDeclaration *TParseContext::addInterfaceBlock(
}
// The instance variable gets created to refer to the interface block type from the AST
// regardless of if there's an instance name. It just has an empty name if there's no instance
// name.
if (!instanceName)
{
instanceName = NewPoolTString("");
}
// regardless of if there's an instance name. It's created as an empty symbol if there is no
// instance name.
TVariable *instanceVariable =
new TVariable(&symbolTable, instanceName, interfaceBlockType, SymbolType::UserDefined);
new TVariable(&symbolTable, instanceName, interfaceBlockType,
instanceName ? SymbolType::UserDefined : SymbolType::Empty);
if (instanceName->empty())
if (instanceVariable->symbolType() == SymbolType::Empty)
{
// define symbols for the members of the interface block
for (size_t memberIndex = 0; memberIndex < fieldList->size(); ++memberIndex)
......@@ -3902,8 +3903,9 @@ void TParseContext::checkIsBelowStructNestingLimit(const TSourceLoc &line, const
// one to the field's struct nesting.
if (1 + field.type()->getDeepestStructNesting() > kWebGLMaxStructNesting)
{
ASSERT(field.type()->getStruct()->name() != nullptr);
std::stringstream reasonStream;
reasonStream << "Reference of struct type " << field.type()->getStruct()->name().c_str()
reasonStream << "Reference of struct type " << field.type()->getStruct()->name()->c_str()
<< " exceeds maximum allowed nesting level of " << kWebGLMaxStructNesting;
std::string reason = reasonStream.str();
error(line, reason.c_str(), field.name().c_str());
......@@ -4770,7 +4772,6 @@ TTypeSpecifierNonArray TParseContext::addStructure(const TSourceLoc &structLine,
SymbolType structSymbolType = SymbolType::UserDefined;
if (structName == nullptr)
{
structName = NewPoolTString("");
structSymbolType = SymbolType::Empty;
}
TStructure *structure = new TStructure(&symbolTable, structName, fieldList, structSymbolType);
......@@ -5780,10 +5781,10 @@ TIntermTyped *TParseContext::addMethod(TFunction *fnCall,
// It's possible for the name pointer in the TFunction to be null in case it gets parsed as
// a constructor. But such a TFunction can't reach here, since the lexer goes into FIELDS
// mode after a dot, which makes type identifiers to be parsed as FIELD_SELECTION instead.
// So accessing fnCall->getName() below is safe.
if (fnCall->name() != "length")
// So accessing fnCall->name() below is safe.
if (*fnCall->name() != "length")
{
error(loc, "invalid method", fnCall->name().c_str());
error(loc, "invalid method", fnCall->name()->c_str());
}
else if (!arguments->empty())
{
......@@ -5816,18 +5817,18 @@ TIntermTyped *TParseContext::addNonConstructorFunctionCall(TFunction *fnCall,
// hidden by a variable name or struct typename.
// If a function is found, check for one with a matching argument list.
bool builtIn;
const TSymbol *symbol = symbolTable.find(fnCall->name(), mShaderVersion, &builtIn);
const TSymbol *symbol = symbolTable.find(*fnCall->name(), mShaderVersion, &builtIn);
if (symbol != nullptr && !symbol->isFunction())
{
error(loc, "function name expected", fnCall->name().c_str());
error(loc, "function name expected", fnCall->name()->c_str());
}
else
{
symbol = symbolTable.find(TFunction::GetMangledNameFromCall(fnCall->name(), *arguments),
symbol = symbolTable.find(TFunction::GetMangledNameFromCall(*fnCall->name(), *arguments),
mShaderVersion, &builtIn);
if (symbol == nullptr)
{
error(loc, "no matching overloaded function found", fnCall->name().c_str());
error(loc, "no matching overloaded function found", fnCall->name()->c_str());
}
else
{
......
......@@ -19,12 +19,15 @@ void RegenerateStructNames::visitSymbol(TIntermSymbol *symbol)
if (!userType)
return;
if (userType->symbolType() == SymbolType::BuiltIn)
if (userType->symbolType() == SymbolType::BuiltIn ||
userType->symbolType() == SymbolType::Empty)
{
// Built-in struct, do not touch it.
// Built-in struct or nameless struct, do not touch it.
return;
}
ASSERT(userType->name() != nullptr);
int uniqueId = userType->uniqueId().get();
ASSERT(mScopeDepth > 0);
......@@ -50,14 +53,14 @@ void RegenerateStructNames::visitSymbol(TIntermSymbol *symbol)
return;
// Map {name} to _webgl_struct_{uniqueId}_{name}.
const char kPrefix[] = "_webgl_struct_";
if (userType->name().find(kPrefix) == 0)
if (userType->name()->find(kPrefix) == 0)
{
// The name has already been regenerated.
return;
}
std::string id = Str(uniqueId);
TString tmp = kPrefix + TString(id.c_str());
tmp += "_" + userType->name();
tmp += "_" + *userType->name();
userType->setName(tmp);
}
......
......@@ -192,8 +192,8 @@ void RemoveUnreferencedVariablesTraverser::removeVariableDeclaration(TIntermDecl
// Already an empty declaration - nothing to do.
return;
}
TVariable *emptyVariable = new TVariable(mSymbolTable, NewPoolTString(""),
declarator->getType(), SymbolType::Empty);
TVariable *emptyVariable =
new TVariable(mSymbolTable, nullptr, declarator->getType(), SymbolType::Empty);
queueReplacementWithParent(node, declarator, new TIntermSymbol(emptyVariable),
OriginalNode::IS_DROPPED);
return;
......
......@@ -40,19 +40,25 @@ TSymbol::TSymbol(TSymbolTable *symbolTable,
{
ASSERT(mSymbolType == SymbolType::BuiltIn || mExtension == TExtension::UNDEFINED);
ASSERT(mName != nullptr || mSymbolType == SymbolType::AngleInternal ||
mSymbolType == SymbolType::NotResolved);
mSymbolType == SymbolType::NotResolved || mSymbolType == SymbolType::Empty);
}
const TString &TSymbol::name() const
const TString *TSymbol::name() const
{
if (mName != nullptr)
if (mName != nullptr || mSymbolType == SymbolType::Empty)
{
return *mName;
return mName;
}
ASSERT(mSymbolType == SymbolType::AngleInternal);
TInfoSinkBase symbolNameOut;
symbolNameOut << "s" << mUniqueId.get();
return *NewPoolTString(symbolNameOut.c_str());
return NewPoolTString(symbolNameOut.c_str());
}
const TString &TSymbol::getMangledName() const
{
ASSERT(mSymbolType != SymbolType::Empty);
return *name();
}
TVariable::TVariable(TSymbolTable *symbolTable,
......@@ -109,6 +115,7 @@ TInterfaceBlock::TInterfaceBlock(TSymbolTable *symbolTable,
mBlockStorage(layoutQualifier.blockStorage),
mBinding(layoutQualifier.binding)
{
ASSERT(name != nullptr);
}
//
......@@ -138,7 +145,7 @@ void TFunction::swapParameters(const TFunction &parametersSource)
const TString *TFunction::buildMangledName() const
{
std::string newName = name().c_str();
std::string newName = name()->c_str();
newName += kFunctionMangledNameSeparator;
for (const auto &p : parameters)
......@@ -181,7 +188,8 @@ bool TSymbolTableLevel::insert(TSymbol *symbol)
bool TSymbolTableLevel::insertUnmangled(TFunction *function)
{
// returning true means symbol was added to the table
tInsertResult result = level.insert(tLevelPair(function->name(), function));
ASSERT(function->name() != nullptr);
tInsertResult result = level.insert(tLevelPair(*function->name(), function));
return result.second;
}
......
......@@ -67,8 +67,8 @@ class TSymbol : angle::NonCopyable
// don't delete name, it's from the pool
}
const TString &name() const;
virtual const TString &getMangledName() const { return name(); }
const TString *name() const;
virtual const TString &getMangledName() const;
virtual bool isFunction() const { return false; }
virtual bool isVariable() const { return false; }
virtual bool isStruct() const { return false; }
......
......@@ -475,12 +475,16 @@ const char *TType::buildMangledName() const
{
case EbtStruct:
mangledName += "struct-";
mangledName += mStructure->name();
if (mStructure->name() != nullptr)
{
mangledName += *mStructure->name();
}
mangledName += mStructure->mangledFieldList();
break;
case EbtInterfaceBlock:
mangledName += "iblock-";
mangledName += mInterfaceBlock->name();
ASSERT(mInterfaceBlock->name() != nullptr);
mangledName += *mInterfaceBlock->name();
mangledName += mInterfaceBlock->mangledFieldList();
break;
default:
......
......@@ -61,7 +61,8 @@ static TString InterfaceBlockFieldTypeString(const TField &field, TLayoutBlockSt
static TString InterfaceBlockStructName(const TInterfaceBlock &interfaceBlock)
{
return DecoratePrivate(interfaceBlock.name()) + "_type";
ASSERT(interfaceBlock.name() != nullptr);
return DecoratePrivate(*interfaceBlock.name()) + "_type";
}
void OutputSamplerIndexArrayInitializer(TInfoSinkBase &out,
......@@ -479,7 +480,8 @@ TString UniformHLSL::uniformBlocksHeader(const ReferencedSymbols &referencedInte
}
unsigned int activeRegister = mUniformBlockRegister;
mUniformBlockRegisterMap[interfaceBlock.name().c_str()] = activeRegister;
ASSERT(interfaceBlock.name() != nullptr);
mUniformBlockRegisterMap[interfaceBlock.name()->c_str()] = activeRegister;
if (instanceName != "" && nodeType.isArray())
{
......@@ -510,7 +512,8 @@ TString UniformHLSL::uniformBlockString(const TInterfaceBlock &interfaceBlock,
{
const TString &arrayIndexString =
(arrayIndex != GL_INVALID_INDEX ? Decorate(str(arrayIndex)) : "");
const TString &blockName = interfaceBlock.name() + arrayIndexString;
ASSERT(interfaceBlock.name() != nullptr);
const TString &blockName = *interfaceBlock.name() + arrayIndexString;
TString hlsl;
hlsl += "cbuffer " + blockName + " : register(b" + str(registerIndex) +
......
......@@ -855,10 +855,10 @@ TString StructNameString(const TStructure &structure)
// translation so that we can link between shader stages.
if (structure.atGlobalScope())
{
return Decorate(structure.name());
return Decorate(*structure.name());
}
return "ss" + str(structure.uniqueId().get()) + "_" + structure.name();
return "ss" + str(structure.uniqueId().get()) + "_" + *structure.name();
}
TString QualifiedStructNameString(const TStructure &structure,
......
......@@ -78,6 +78,7 @@
'<(angle_path)/src/tests/compiler_tests/QualificationOrderESSL31_test.cpp',
'<(angle_path)/src/tests/compiler_tests/QualificationOrder_test.cpp',
'<(angle_path)/src/tests/compiler_tests/RecordConstantPrecision_test.cpp',
'<(angle_path)/src/tests/compiler_tests/RegenerateStructNames_test.cpp',
'<(angle_path)/src/tests/compiler_tests/RemovePow_test.cpp',
'<(angle_path)/src/tests/compiler_tests/RemoveUnreferencedVariables_test.cpp',
'<(angle_path)/src/tests/compiler_tests/RewriteDoWhile_test.cpp',
......
......@@ -809,17 +809,61 @@ TEST_F(CollectHashedVertexVariablesTest, InstancedInterfaceBlock)
EXPECT_TRUE(field.fields.empty());
}
// Test a struct uniform where the struct does have a name.
TEST_F(CollectHashedVertexVariablesTest, StructUniform)
{
const std::string &shaderString =
"#version 300 es\n"
"struct sType {\n"
" float field;\n"
"};"
"uniform sType u;"
"void main() {\n"
" gl_Position = vec4(u.field, 0.0, 0.0, 1.0);\n"
"}\n";
R"(#version 300 es
struct sType
{
float field;
};
uniform sType u;
void main()
{
gl_Position = vec4(u.field, 0.0, 0.0, 1.0);
})";
compile(shaderString);
const auto &uniforms = mTranslator->getUniforms();
ASSERT_EQ(1u, uniforms.size());
const Uniform &uniform = uniforms[0];
EXPECT_FALSE(uniform.isArray());
EXPECT_EQ("u", uniform.name);
EXPECT_EQ("webgl_1", uniform.mappedName);
EXPECT_EQ("sType", uniform.structName);
EXPECT_TRUE(uniform.staticUse);
ASSERT_EQ(1u, uniform.fields.size());
const ShaderVariable &field = uniform.fields[0];
EXPECT_GLENUM_EQ(GL_HIGH_FLOAT, field.precision);
// EXPECT_TRUE(field.staticUse); // we don't yet support struct static use
EXPECT_GLENUM_EQ(GL_FLOAT, field.type);
EXPECT_EQ("field", field.name);
EXPECT_EQ("webgl_5", field.mappedName);
EXPECT_TRUE(field.fields.empty());
}
// Test a struct uniform where the struct doesn't have a name.
TEST_F(CollectHashedVertexVariablesTest, NamelessStructUniform)
{
const std::string &shaderString =
R"(#version 300 es
uniform struct
{
float field;
} u;
void main()
{
gl_Position = vec4(u.field, 0.0, 0.0, 1.0);
})";
compile(shaderString);
......@@ -831,6 +875,7 @@ TEST_F(CollectHashedVertexVariablesTest, StructUniform)
EXPECT_FALSE(uniform.isArray());
EXPECT_EQ("u", uniform.name);
EXPECT_EQ("webgl_1", uniform.mappedName);
EXPECT_EQ("", uniform.structName);
EXPECT_TRUE(uniform.staticUse);
ASSERT_EQ(1u, uniform.fields.size());
......
......@@ -167,7 +167,8 @@ class FindStructByName final : public TIntermTraverser
TStructure *structure = symbol->getTypePointer()->getStruct();
if (structure != nullptr && structure->name() == mStructName)
if (structure != nullptr && structure->name() != nullptr &&
*structure->name() == mStructName)
{
mStructure = structure;
}
......
//
// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// RegenerateStructNames_test.cpp:
// Tests for regenerating struct names.
//
#include "GLSLANG/ShaderLang.h"
#include "angle_gl.h"
#include "gtest/gtest.h"
#include "tests/test_utils/compiler_test.h"
using namespace sh;
class RegenerateStructNamesTest : public MatchOutputCodeTest
{
public:
RegenerateStructNamesTest()
: MatchOutputCodeTest(GL_FRAGMENT_SHADER, SH_REGENERATE_STRUCT_NAMES, SH_ESSL_OUTPUT)
{
}
};
// Test that a struct defined in a function scope is renamed. The global struct that's used as a
// type of a uniform cannot be renamed.
TEST_F(RegenerateStructNamesTest, GlobalStructAndLocalStructWithTheSameName)
{
const std::string &shaderString =
R"(precision mediump float;
struct myStruct
{
float foo;
};
uniform myStruct us;
void main()
{
struct myStruct
{
vec2 bar;
};
myStruct scoped;
scoped.bar = vec2(1.0, 2.0) * us.foo;
gl_FragColor = vec4(scoped.bar, 0.0, 1.0);
})";
compile(shaderString);
EXPECT_TRUE(foundInCode("struct _umyStruct"));
EXPECT_TRUE(foundInCode("struct _u_webgl_struct_"));
}
// Test that a nameless struct is handled gracefully.
TEST_F(RegenerateStructNamesTest, NamelessStruct)
{
const std::string &shaderString =
R"(precision mediump float;
uniform float u;
void main()
{
struct
{
vec2 bar;
} scoped;
scoped.bar = vec2(1.0, 2.0) * u;
gl_FragColor = vec4(scoped.bar, 0.0, 1.0);
})";
compile(shaderString);
EXPECT_TRUE(foundInCode("struct"));
}
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