Support ESSL 3.00 EXT_blend_func_extended shaders
This adds support for the index layout qualifier that's used in
EXT_blend_func_extended to set whether a fragment output should be
bound to the primary or secondary blend source color.
Output locations are now validated correctly so that two outputs can
have the same location as long as they have a different index. Some
tests are fixed to allow this.
BUG=angleproject:1085
TEST=angle_unittests
Change-Id: I1de3ad1406398952287791eca367562bed59d380
Reviewed-on: https://chromium-review.googlesource.com/1245982
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index 7ce9acc..c3393ee 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -1130,6 +1130,25 @@
(*variable) = new TVariable(&symbolTable, identifier, type, SymbolType::UserDefined);
+ ASSERT(type->getLayoutQualifier().index == -1 ||
+ (isExtensionEnabled(TExtension::EXT_blend_func_extended) &&
+ mShaderType == GL_FRAGMENT_SHADER && mShaderVersion >= 300));
+ if (type->getQualifier() == EvqFragmentOut)
+ {
+ if (type->getLayoutQualifier().index != -1 && type->getLayoutQualifier().location == -1)
+ {
+ error(line,
+ "If index layout qualifier is specified for a fragment output, location must "
+ "also be specified.",
+ "index");
+ return false;
+ }
+ }
+ else
+ {
+ checkIndexIsNotSpecified(line, type->getLayoutQualifier().index);
+ }
+
checkBindingIsValid(line, *type);
bool needsReservedCheck = true;
@@ -1376,6 +1395,11 @@
// error. It is assumed that this applies to empty declarations as well.
error(location, "empty array declaration needs to specify a size", "");
}
+
+ if (type.getQualifier() != EvqFragmentOut)
+ {
+ checkIndexIsNotSpecified(location, type.getLayoutQualifier().index);
+ }
}
// These checks are done for all declarations that are non-empty. They're done for non-empty
@@ -1596,6 +1620,17 @@
}
}
+void TParseContext::checkIndexIsNotSpecified(const TSourceLoc &location, int index)
+{
+ if (index != -1)
+ {
+ error(location,
+ "invalid layout qualifier: only valid when used with a fragment shader output in "
+ "ESSL version >= 3.00 and EXT_blend_func_extended is enabled",
+ "index");
+ }
+}
+
void TParseContext::checkBindingIsNotSpecified(const TSourceLoc &location, int binding)
{
if (binding != -1)
@@ -2981,6 +3016,8 @@
return;
}
+ checkIndexIsNotSpecified(typeQualifier.line, layoutQualifier.index);
+
checkBindingIsNotSpecified(typeQualifier.line, layoutQualifier.binding);
checkMemoryQualifierIsNotSpecified(typeQualifier.memoryQualifier, typeQualifier.line);
@@ -3615,6 +3652,8 @@
arraySize = checkIsValidArraySize(arrayIndexLine, arrayIndex);
}
+ checkIndexIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier.index);
+
if (mShaderVersion < 310)
{
checkBindingIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier.binding);
@@ -3706,6 +3745,7 @@
// check layout qualifiers
TLayoutQualifier fieldLayoutQualifier = fieldType->getLayoutQualifier();
checkLocationIsNotSpecified(field->line(), fieldLayoutQualifier);
+ checkIndexIsNotSpecified(field->line(), fieldLayoutQualifier.index);
checkBindingIsNotSpecified(field->line(), fieldLayoutQualifier.binding);
if (fieldLayoutQualifier.blockStorage != EbsUnspecified)
@@ -4411,6 +4451,26 @@
}
}
+void TParseContext::parseIndexLayoutQualifier(int intValue,
+ const TSourceLoc &intValueLine,
+ const std::string &intValueString,
+ int *index)
+{
+ // EXT_blend_func_extended specifies that most validation should happen at link time, but since
+ // we're validating output variable locations at compile time, it makes sense to validate that
+ // index is 0 or 1 also at compile time. Also since we use "-1" as a placeholder for unspecified
+ // index, we can't accept it here.
+ if (intValue < 0 || intValue > 1)
+ {
+ error(intValueLine, "out of range: index layout qualifier can only be 0 or 1",
+ intValueString.c_str());
+ }
+ else
+ {
+ *index = intValue;
+ }
+}
+
TLayoutQualifier TParseContext::parseLayoutQualifier(const ImmutableString &qualifierType,
const TSourceLoc &qualifierTypeLine,
int intValue,
@@ -4492,7 +4552,11 @@
{
parseMaxVertices(intValue, intValueLine, intValueString, &qualifier.maxVertices);
}
-
+ else if (qualifierType == "index" && mShaderType == GL_FRAGMENT_SHADER &&
+ checkCanUseExtension(qualifierTypeLine, TExtension::EXT_blend_func_extended))
+ {
+ parseIndexLayoutQualifier(intValue, intValueLine, intValueString, &qualifier.index);
+ }
else
{
error(qualifierTypeLine, "invalid layout qualifier", qualifierType);
@@ -4781,6 +4845,8 @@
checkMemoryQualifierIsNotSpecified(field.type()->getMemoryQualifier(), field.line());
+ checkIndexIsNotSpecified(field.line(), field.type()->getLayoutQualifier().index);
+
checkBindingIsNotSpecified(field.line(), field.type()->getLayoutQualifier().binding);
checkLocationIsNotSpecified(field.line(), field.type()->getLayoutQualifier());