Commit cc2a10e9 by jchen10 Committed by Commit Bot

Unify opaque type validation in GLSL parsing

Refactor separate sampler and image validations into unified opaque type handling. This paves way for adding atomic counter, another new opaque type. BUG=angleproject:1729 Change-Id: I201d28e31c84534db43e656d518650e378bab76c Reviewed-on: https://chromium-review.googlesource.com/493618Reviewed-by: 's avatarOlli Etuaho <oetuaho@nvidia.com> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Corentin Wallez <cwallez@chromium.org>
parent 7142f6ce
...@@ -35,7 +35,7 @@ bool ContainsSampler(const TType &type) ...@@ -35,7 +35,7 @@ bool ContainsSampler(const TType &type)
if (IsSampler(type.getBasicType())) if (IsSampler(type.getBasicType()))
return true; return true;
if (type.getBasicType() == EbtStruct || type.isInterfaceBlock()) if (type.getBasicType() == EbtStruct)
{ {
const TFieldList &fields = type.getStruct()->fields(); const TFieldList &fields = type.getStruct()->fields();
for (unsigned int i = 0; i < fields.size(); ++i) for (unsigned int i = 0; i < fields.size(); ++i)
...@@ -48,24 +48,6 @@ bool ContainsSampler(const TType &type) ...@@ -48,24 +48,6 @@ bool ContainsSampler(const TType &type)
return false; return false;
} }
bool ContainsImage(const TType &type)
{
if (IsImage(type.getBasicType()))
return true;
if (type.getBasicType() == EbtStruct || type.isInterfaceBlock())
{
const TFieldList &fields = type.getStruct()->fields();
for (unsigned int i = 0; i < fields.size(); ++i)
{
if (ContainsImage(*fields[i]->type()))
return true;
}
}
return false;
}
// Get a token from an image argument to use as an error message token. // Get a token from an image argument to use as an error message token.
const char *GetImageArgumentToken(TIntermTyped *imageNode) const char *GetImageArgumentToken(TIntermTyped *imageNode)
{ {
...@@ -340,14 +322,9 @@ void TParseContext::checkPrecisionSpecified(const TSourceLoc &line, ...@@ -340,14 +322,9 @@ void TParseContext::checkPrecisionSpecified(const TSourceLoc &line,
error(line, "No precision specified (int)", ""); error(line, "No precision specified (int)", "");
return; return;
default: default:
if (IsSampler(type)) if (IsOpaqueType(type))
{
error(line, "No precision specified (sampler)", "");
return;
}
if (IsImage(type))
{ {
error(line, "No precision specified (image)", ""); error(line, "No precision specified", getBasicString(type));
return; return;
} }
} }
...@@ -389,7 +366,7 @@ bool TParseContext::checkCanBeLValue(const TSourceLoc &line, const char *op, TIn ...@@ -389,7 +366,7 @@ bool TParseContext::checkCanBeLValue(const TSourceLoc &line, const char *op, TIn
return false; return false;
} }
const char *message = 0; std::string message;
switch (node->getQualifier()) switch (node->getQualifier())
{ {
case EvqConst: case EvqConst:
...@@ -454,17 +431,14 @@ bool TParseContext::checkCanBeLValue(const TSourceLoc &line, const char *op, TIn ...@@ -454,17 +431,14 @@ bool TParseContext::checkCanBeLValue(const TSourceLoc &line, const char *op, TIn
{ {
message = "can't modify void"; message = "can't modify void";
} }
if (IsSampler(node->getBasicType())) if (IsOpaqueType(node->getBasicType()))
{
message = "can't modify a sampler";
}
if (IsImage(node->getBasicType()))
{ {
message = "can't modify an image"; message = "can't modify a variable with type ";
message += getBasicString(node->getBasicType());
} }
} }
if (message == 0 && binaryNode == 0 && symNode == 0) if (message.empty() && binaryNode == 0 && symNode == 0)
{ {
error(line, "l-value required", op); error(line, "l-value required", op);
...@@ -474,7 +448,7 @@ bool TParseContext::checkCanBeLValue(const TSourceLoc &line, const char *op, TIn ...@@ -474,7 +448,7 @@ bool TParseContext::checkCanBeLValue(const TSourceLoc &line, const char *op, TIn
// //
// Everything else is okay, no error. // Everything else is okay, no error.
// //
if (message == 0) if (message.empty())
return true; return true;
// //
...@@ -686,14 +660,11 @@ bool TParseContext::checkConstructorArguments(const TSourceLoc &line, ...@@ -686,14 +660,11 @@ bool TParseContext::checkConstructorArguments(const TSourceLoc &line,
{ {
TIntermTyped *argTyped = argNode->getAsTyped(); TIntermTyped *argTyped = argNode->getAsTyped();
ASSERT(argTyped != nullptr); ASSERT(argTyped != nullptr);
if (op != EOpConstructStruct && IsSampler(argTyped->getBasicType())) if (op != EOpConstructStruct && IsOpaqueType(argTyped->getBasicType()))
{ {
error(line, "cannot convert a sampler", "constructor"); std::string reason("cannot convert a variable with type ");
return false; reason += getBasicString(argTyped->getBasicType());
} error(line, reason.c_str(), "constructor");
if (op != EOpConstructStruct && IsImage(argTyped->getBasicType()))
{
error(line, "cannot convert an image", "constructor");
return false; return false;
} }
if (argTyped->getBasicType() == EbtVoid) if (argTyped->getBasicType() == EbtVoid)
...@@ -780,9 +751,9 @@ void TParseContext::checkIsScalarBool(const TSourceLoc &line, const TPublicType ...@@ -780,9 +751,9 @@ void TParseContext::checkIsScalarBool(const TSourceLoc &line, const TPublicType
} }
} }
bool TParseContext::checkIsNotSampler(const TSourceLoc &line, bool TParseContext::checkIsNotOpaqueType(const TSourceLoc &line,
const TTypeSpecifierNonArray &pType, const TTypeSpecifierNonArray &pType,
const char *reason) const char *reason)
{ {
if (pType.type == EbtStruct) if (pType.type == EbtStruct)
{ {
...@@ -794,10 +765,11 @@ bool TParseContext::checkIsNotSampler(const TSourceLoc &line, ...@@ -794,10 +765,11 @@ bool TParseContext::checkIsNotSampler(const TSourceLoc &line,
error(line, reasonStr.c_str(), getBasicString(pType.type)); error(line, reasonStr.c_str(), getBasicString(pType.type));
return false; return false;
} }
// only samplers need to be checked from structs, since other opaque types can't be struct
// members.
return true; return true;
} }
else if (IsSampler(pType.type)) else if (IsOpaqueType(pType.type))
{ {
error(line, reason, getBasicString(pType.type)); error(line, reason, getBasicString(pType.type));
return false; return false;
...@@ -806,34 +778,6 @@ bool TParseContext::checkIsNotSampler(const TSourceLoc &line, ...@@ -806,34 +778,6 @@ bool TParseContext::checkIsNotSampler(const TSourceLoc &line,
return true; return true;
} }
bool TParseContext::checkIsNotImage(const TSourceLoc &line,
const TTypeSpecifierNonArray &pType,
const char *reason)
{
if (pType.type == EbtStruct)
{
if (ContainsImage(*pType.userDef))
{
std::stringstream reasonStream;
reasonStream << reason << " (structure contains an image)";
std::string reasonStr = reasonStream.str();
error(line, reasonStr.c_str(), getBasicString(pType.type));
return false;
}
return true;
}
else if (IsImage(pType.type))
{
error(line, reason, getBasicString(pType.type));
return false;
}
return true;
}
void TParseContext::checkDeclaratorLocationIsNotSpecified(const TSourceLoc &line, void TParseContext::checkDeclaratorLocationIsNotSpecified(const TSourceLoc &line,
const TPublicType &pType) const TPublicType &pType)
{ {
...@@ -863,29 +807,10 @@ void TParseContext::checkOutParameterIsNotOpaqueType(const TSourceLoc &line, ...@@ -863,29 +807,10 @@ void TParseContext::checkOutParameterIsNotOpaqueType(const TSourceLoc &line,
TQualifier qualifier, TQualifier qualifier,
const TType &type) const TType &type)
{ {
checkOutParameterIsNotSampler(line, qualifier, type);
checkOutParameterIsNotImage(line, qualifier, type);
}
void TParseContext::checkOutParameterIsNotSampler(const TSourceLoc &line,
TQualifier qualifier,
const TType &type)
{
ASSERT(qualifier == EvqOut || qualifier == EvqInOut); ASSERT(qualifier == EvqOut || qualifier == EvqInOut);
if (IsSampler(type.getBasicType())) if (IsOpaqueType(type.getBasicType()))
{ {
error(line, "samplers cannot be output parameters", type.getBasicString()); error(line, "opaque types cannot be output parameters", type.getBasicString());
}
}
void TParseContext::checkOutParameterIsNotImage(const TSourceLoc &line,
TQualifier qualifier,
const TType &type)
{
ASSERT(qualifier == EvqOut || qualifier == EvqInOut);
if (IsImage(type.getBasicType()))
{
error(line, "images cannot be output parameters", type.getBasicString());
} }
} }
...@@ -1227,16 +1152,10 @@ void TParseContext::nonEmptyDeclarationErrorCheck(const TPublicType &publicType, ...@@ -1227,16 +1152,10 @@ void TParseContext::nonEmptyDeclarationErrorCheck(const TPublicType &publicType,
default: default:
break; break;
} }
std::string reason(getBasicString(publicType.getBasicType()));
if (publicType.qualifier != EvqUniform && reason += "s must be uniform";
!checkIsNotSampler(identifierLocation, publicType.typeSpecifierNonArray,
"samplers must be uniform"))
{
return;
}
if (publicType.qualifier != EvqUniform && if (publicType.qualifier != EvqUniform &&
!checkIsNotImage(identifierLocation, publicType.typeSpecifierNonArray, !checkIsNotOpaqueType(identifierLocation, publicType.typeSpecifierNonArray, reason.c_str()))
"images must be uniform"))
{ {
return; return;
} }
...@@ -2757,10 +2676,10 @@ TFunction *TParseContext::parseFunctionHeader(const TPublicType &type, ...@@ -2757,10 +2676,10 @@ TFunction *TParseContext::parseFunctionHeader(const TPublicType &type,
{ {
error(location, "no qualifiers allowed for function return", "layout"); error(location, "no qualifiers allowed for function return", "layout");
} }
// make sure a sampler or an image is not involved as well... // make sure an opaque type is not involved as well...
checkIsNotSampler(location, type.typeSpecifierNonArray, std::string reason(getBasicString(type.getBasicType()));
"samplers can't be function return values"); reason += "s can't be function return values";
checkIsNotImage(location, type.typeSpecifierNonArray, "images can't be function return values"); checkIsNotOpaqueType(location, type.typeSpecifierNonArray, reason.c_str());
if (mShaderVersion < 300) if (mShaderVersion < 300)
{ {
// Array return values are forbidden, but there's also no valid syntax for declaring array // Array return values are forbidden, but there's also no valid syntax for declaring array
...@@ -2911,18 +2830,12 @@ TIntermDeclaration *TParseContext::addInterfaceBlock( ...@@ -2911,18 +2830,12 @@ TIntermDeclaration *TParseContext::addInterfaceBlock(
{ {
TField *field = (*fieldList)[memberIndex]; TField *field = (*fieldList)[memberIndex];
TType *fieldType = field->type(); TType *fieldType = field->type();
if (IsSampler(fieldType->getBasicType())) if (IsOpaqueType(fieldType->getBasicType()))
{ {
error(field->line(), std::string reason("unsupported type - ");
"unsupported type - sampler types are not allowed in interface blocks", reason += fieldType->getBasicString();
fieldType->getBasicString()); reason += " types are not allowed in interface blocks";
} error(field->line(), reason.c_str(), fieldType->getBasicString());
if (IsImage(fieldType->getBasicType()))
{
error(field->line(),
"unsupported type - image types are not allowed in interface blocks",
fieldType->getBasicString());
} }
const TQualifier qualifier = fieldType->getQualifier(); const TQualifier qualifier = fieldType->getQualifier();
...@@ -3856,6 +3769,9 @@ bool TParseContext::binaryOpCommonCheck(TOperator op, ...@@ -3856,6 +3769,9 @@ bool TParseContext::binaryOpCommonCheck(TOperator op,
TIntermTyped *right, TIntermTyped *right,
const TSourceLoc &loc) const TSourceLoc &loc)
{ {
// TODO(jie.a.chen@intel.com): Validate opaque type variables can only be operands in array
// indexing, structure member selection, and parentheses expressions.
if (left->getType().getStruct() || right->getType().getStruct()) if (left->getType().getStruct() || right->getType().getStruct())
{ {
switch (op) switch (op)
...@@ -3979,13 +3895,6 @@ bool TParseContext::binaryOpCommonCheck(TOperator op, ...@@ -3979,13 +3895,6 @@ bool TParseContext::binaryOpCommonCheck(TOperator op,
return false; return false;
} }
if ((op == EOpAssign || op == EOpInitialize) &&
left->getType().isStructureContainingImages())
{
error(loc, "undefined operation for structs containing images",
GetOperatorString(op));
return false;
}
if ((left->getNominalSize() != right->getNominalSize()) || if ((left->getNominalSize() != right->getNominalSize()) ||
(left->getSecondarySize() != right->getSecondarySize())) (left->getSecondarySize() != right->getSecondarySize()))
{ {
......
...@@ -123,12 +123,9 @@ class TParseContext : angle::NonCopyable ...@@ -123,12 +123,9 @@ class TParseContext : angle::NonCopyable
bool checkIsNonVoid(const TSourceLoc &line, const TString &identifier, const TBasicType &type); bool checkIsNonVoid(const TSourceLoc &line, const TString &identifier, const TBasicType &type);
void checkIsScalarBool(const TSourceLoc &line, const TIntermTyped *type); void checkIsScalarBool(const TSourceLoc &line, const TIntermTyped *type);
void checkIsScalarBool(const TSourceLoc &line, const TPublicType &pType); void checkIsScalarBool(const TSourceLoc &line, const TPublicType &pType);
bool checkIsNotSampler(const TSourceLoc &line, bool checkIsNotOpaqueType(const TSourceLoc &line,
const TTypeSpecifierNonArray &pType, const TTypeSpecifierNonArray &pType,
const char *reason); const char *reason);
bool checkIsNotImage(const TSourceLoc &line,
const TTypeSpecifierNonArray &pType,
const char *reason);
void checkDeclaratorLocationIsNotSpecified(const TSourceLoc &line, const TPublicType &pType); void checkDeclaratorLocationIsNotSpecified(const TSourceLoc &line, const TPublicType &pType);
void checkLocationIsNotSpecified(const TSourceLoc &location, void checkLocationIsNotSpecified(const TSourceLoc &location,
const TLayoutQualifier &layoutQualifier); const TLayoutQualifier &layoutQualifier);
...@@ -384,15 +381,9 @@ class TParseContext : angle::NonCopyable ...@@ -384,15 +381,9 @@ class TParseContext : angle::NonCopyable
// Assumes that multiplication op has already been set based on the types. // Assumes that multiplication op has already been set based on the types.
bool isMultiplicationTypeCombinationValid(TOperator op, const TType &left, const TType &right); bool isMultiplicationTypeCombinationValid(TOperator op, const TType &left, const TType &right);
void checkOutParameterIsNotImage(const TSourceLoc &line,
TQualifier qualifier,
const TType &type);
void checkOutParameterIsNotOpaqueType(const TSourceLoc &line, void checkOutParameterIsNotOpaqueType(const TSourceLoc &line,
TQualifier qualifier, TQualifier qualifier,
const TType &type); const TType &type);
void checkOutParameterIsNotSampler(const TSourceLoc &line,
TQualifier qualifier,
const TType &type);
void checkInternalFormatIsNotSpecified(const TSourceLoc &location, void checkInternalFormatIsNotSpecified(const TSourceLoc &location,
TLayoutImageInternalFormat internalFormat); TLayoutImageInternalFormat internalFormat);
......
...@@ -526,17 +526,6 @@ bool TStructure::containsSamplers() const ...@@ -526,17 +526,6 @@ bool TStructure::containsSamplers() const
return false; return false;
} }
bool TStructure::containsImages() const
{
for (size_t i = 0; i < mFields->size(); ++i)
{
const TType *fieldType = (*mFields)[i]->type();
if (IsImage(fieldType->getBasicType()) || fieldType->isStructureContainingImages())
return true;
}
return false;
}
void TStructure::createSamplerSymbols(const TString &structName, void TStructure::createSamplerSymbols(const TString &structName,
const TString &structAPIName, const TString &structAPIName,
const unsigned int arrayOfStructsSize, const unsigned int arrayOfStructsSize,
......
...@@ -98,7 +98,6 @@ class TStructure : public TFieldListCollection ...@@ -98,7 +98,6 @@ class TStructure : public TFieldListCollection
bool containsArrays() const; bool containsArrays() const;
bool containsType(TBasicType t) const; bool containsType(TBasicType t) const;
bool containsSamplers() const; bool containsSamplers() const;
bool containsImages() const;
void createSamplerSymbols(const TString &structName, void createSamplerSymbols(const TString &structName,
const TString &structAPIName, const TString &structAPIName,
...@@ -468,11 +467,6 @@ class TType ...@@ -468,11 +467,6 @@ class TType
return structure ? structure->containsSamplers() : false; return structure ? structure->containsSamplers() : false;
} }
bool isStructureContainingImages() const
{
return structure ? structure->containsImages() : false;
}
void createSamplerSymbols(const TString &structName, void createSamplerSymbols(const TString &structName,
const TString &structAPIName, const TString &structAPIName,
const unsigned int arrayOfStructsSize, const unsigned int arrayOfStructsSize,
......
...@@ -3762,3 +3762,20 @@ TEST_F(FragmentShaderValidationTest, UniformLocationEmptyDeclaration) ...@@ -3762,3 +3762,20 @@ TEST_F(FragmentShaderValidationTest, UniformLocationEmptyDeclaration)
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog; FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
} }
} }
// Test function parameters of opaque type can't be l-value too.
TEST_F(FragmentShaderValidationTest, OpaqueParameterCanNotBeLValue)
{
const std::string &shaderString =
"#version 310 es\n"
"uniform sampler2D s;\n"
"void foo(sampler2D as) {\n"
" as = s;\n"
"}\n"
"void main() {}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
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