Commit a78092cb by Olli Etuaho Committed by Commit Bot

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: 's avatarGeoff Lang <geofflang@chromium.org>
parent 79207e6e
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
// Version number for shader translation API. // Version number for shader translation API.
// It is incremented every time the API changes. // It is incremented every time the API changes.
#define ANGLE_SH_VERSION 199 #define ANGLE_SH_VERSION 200
enum ShShaderSpec enum ShShaderSpec
{ {
......
...@@ -203,6 +203,9 @@ struct OutputVariable : public VariableWithLocation ...@@ -203,6 +203,9 @@ struct OutputVariable : public VariableWithLocation
OutputVariable &operator=(const OutputVariable &other); OutputVariable &operator=(const OutputVariable &other);
bool operator==(const OutputVariable &other) const; bool operator==(const OutputVariable &other) const;
bool operator!=(const OutputVariable &other) const { return !operator==(other); } bool operator!=(const OutputVariable &other) const { return !operator==(other); }
// From EXT_blend_func_extended.
int index;
}; };
struct InterfaceBlockField : public ShaderVariable struct InterfaceBlockField : public ShaderVariable
......
...@@ -729,7 +729,8 @@ struct TLayoutQualifier ...@@ -729,7 +729,8 @@ struct TLayoutQualifier
return location == -1 && binding == -1 && offset == -1 && numViews == -1 && yuv == false && return location == -1 && binding == -1 && offset == -1 && numViews == -1 && yuv == false &&
matrixPacking == EmpUnspecified && blockStorage == EbsUnspecified && matrixPacking == EmpUnspecified && blockStorage == EbsUnspecified &&
!localSize.isAnyValueSet() && imageInternalFormat == EiifUnspecified && !localSize.isAnyValueSet() && imageInternalFormat == EiifUnspecified &&
primitiveType == EptUndefined && invocations == 0 && maxVertices == -1; primitiveType == EptUndefined && invocations == 0 && maxVertices == -1 &&
index == -1;
} }
bool isCombinationValid() const bool isCombinationValid() const
...@@ -739,7 +740,7 @@ struct TLayoutQualifier ...@@ -739,7 +740,7 @@ struct TLayoutQualifier
bool geometryShaderSpecified = bool geometryShaderSpecified =
(primitiveType != EptUndefined) || (invocations != 0) || (maxVertices != -1); (primitiveType != EptUndefined) || (invocations != 0) || (maxVertices != -1);
bool otherLayoutQualifiersSpecified = bool otherLayoutQualifiersSpecified =
(location != -1 || binding != -1 || matrixPacking != EmpUnspecified || (location != -1 || binding != -1 || index != -1 || matrixPacking != EmpUnspecified ||
blockStorage != EbsUnspecified || imageInternalFormat != EiifUnspecified); blockStorage != EbsUnspecified || imageInternalFormat != EiifUnspecified);
// we can have either the work group size specified, or number of views, // we can have either the work group size specified, or number of views,
...@@ -779,6 +780,9 @@ struct TLayoutQualifier ...@@ -779,6 +780,9 @@ struct TLayoutQualifier
int invocations; int invocations;
int maxVertices; int maxVertices;
// EXT_blend_func_extended fragment output layout qualifier
int index;
private: private:
explicit constexpr TLayoutQualifier(int /*placeholder*/) explicit constexpr TLayoutQualifier(int /*placeholder*/)
: location(-1), : location(-1),
...@@ -793,7 +797,8 @@ struct TLayoutQualifier ...@@ -793,7 +797,8 @@ struct TLayoutQualifier
yuv(false), yuv(false),
primitiveType(EptUndefined), primitiveType(EptUndefined),
invocations(0), invocations(0),
maxVertices(-1) maxVertices(-1),
index(-1)
{ {
} }
}; };
......
...@@ -648,6 +648,7 @@ OutputVariable CollectVariablesTraverser::recordOutputVariable(const TIntermSymb ...@@ -648,6 +648,7 @@ OutputVariable CollectVariablesTraverser::recordOutputVariable(const TIntermSymb
setCommonVariableProperties(type, variable.variable(), &outputVariable); setCommonVariableProperties(type, variable.variable(), &outputVariable);
outputVariable.location = type.getLayoutQualifier().location; outputVariable.location = type.getLayoutQualifier().location;
outputVariable.index = type.getLayoutQualifier().index;
return outputVariable; return outputVariable;
} }
......
...@@ -1130,6 +1130,25 @@ bool TParseContext::declareVariable(const TSourceLoc &line, ...@@ -1130,6 +1130,25 @@ bool TParseContext::declareVariable(const TSourceLoc &line,
(*variable) = new TVariable(&symbolTable, identifier, type, SymbolType::UserDefined); (*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); checkBindingIsValid(line, *type);
bool needsReservedCheck = true; bool needsReservedCheck = true;
...@@ -1376,6 +1395,11 @@ void TParseContext::emptyDeclarationErrorCheck(const TType &type, const TSourceL ...@@ -1376,6 +1395,11 @@ void TParseContext::emptyDeclarationErrorCheck(const TType &type, const TSourceL
// error. It is assumed that this applies to empty declarations as well. // error. It is assumed that this applies to empty declarations as well.
error(location, "empty array declaration needs to specify a size", ""); 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 // These checks are done for all declarations that are non-empty. They're done for non-empty
...@@ -1596,6 +1620,17 @@ void TParseContext::checkInternalFormatIsNotSpecified(const TSourceLoc &location ...@@ -1596,6 +1620,17 @@ void TParseContext::checkInternalFormatIsNotSpecified(const TSourceLoc &location
} }
} }
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) void TParseContext::checkBindingIsNotSpecified(const TSourceLoc &location, int binding)
{ {
if (binding != -1) if (binding != -1)
...@@ -2981,6 +3016,8 @@ void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &type ...@@ -2981,6 +3016,8 @@ void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &type
return; return;
} }
checkIndexIsNotSpecified(typeQualifier.line, layoutQualifier.index);
checkBindingIsNotSpecified(typeQualifier.line, layoutQualifier.binding); checkBindingIsNotSpecified(typeQualifier.line, layoutQualifier.binding);
checkMemoryQualifierIsNotSpecified(typeQualifier.memoryQualifier, typeQualifier.line); checkMemoryQualifierIsNotSpecified(typeQualifier.memoryQualifier, typeQualifier.line);
...@@ -3615,6 +3652,8 @@ TIntermDeclaration *TParseContext::addInterfaceBlock( ...@@ -3615,6 +3652,8 @@ TIntermDeclaration *TParseContext::addInterfaceBlock(
arraySize = checkIsValidArraySize(arrayIndexLine, arrayIndex); arraySize = checkIsValidArraySize(arrayIndexLine, arrayIndex);
} }
checkIndexIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier.index);
if (mShaderVersion < 310) if (mShaderVersion < 310)
{ {
checkBindingIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier.binding); checkBindingIsNotSpecified(typeQualifier.line, typeQualifier.layoutQualifier.binding);
...@@ -3706,6 +3745,7 @@ TIntermDeclaration *TParseContext::addInterfaceBlock( ...@@ -3706,6 +3745,7 @@ TIntermDeclaration *TParseContext::addInterfaceBlock(
// check layout qualifiers // check layout qualifiers
TLayoutQualifier fieldLayoutQualifier = fieldType->getLayoutQualifier(); TLayoutQualifier fieldLayoutQualifier = fieldType->getLayoutQualifier();
checkLocationIsNotSpecified(field->line(), fieldLayoutQualifier); checkLocationIsNotSpecified(field->line(), fieldLayoutQualifier);
checkIndexIsNotSpecified(field->line(), fieldLayoutQualifier.index);
checkBindingIsNotSpecified(field->line(), fieldLayoutQualifier.binding); checkBindingIsNotSpecified(field->line(), fieldLayoutQualifier.binding);
if (fieldLayoutQualifier.blockStorage != EbsUnspecified) if (fieldLayoutQualifier.blockStorage != EbsUnspecified)
...@@ -4411,6 +4451,26 @@ void TParseContext::parseMaxVertices(int intValue, ...@@ -4411,6 +4451,26 @@ void TParseContext::parseMaxVertices(int intValue,
} }
} }
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, TLayoutQualifier TParseContext::parseLayoutQualifier(const ImmutableString &qualifierType,
const TSourceLoc &qualifierTypeLine, const TSourceLoc &qualifierTypeLine,
int intValue, int intValue,
...@@ -4492,7 +4552,11 @@ TLayoutQualifier TParseContext::parseLayoutQualifier(const ImmutableString &qual ...@@ -4492,7 +4552,11 @@ TLayoutQualifier TParseContext::parseLayoutQualifier(const ImmutableString &qual
{ {
parseMaxVertices(intValue, intValueLine, intValueString, &qualifier.maxVertices); 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 else
{ {
error(qualifierTypeLine, "invalid layout qualifier", qualifierType); error(qualifierTypeLine, "invalid layout qualifier", qualifierType);
...@@ -4781,6 +4845,8 @@ TTypeSpecifierNonArray TParseContext::addStructure(const TSourceLoc &structLine, ...@@ -4781,6 +4845,8 @@ TTypeSpecifierNonArray TParseContext::addStructure(const TSourceLoc &structLine,
checkMemoryQualifierIsNotSpecified(field.type()->getMemoryQualifier(), field.line()); checkMemoryQualifierIsNotSpecified(field.type()->getMemoryQualifier(), field.line());
checkIndexIsNotSpecified(field.line(), field.type()->getLayoutQualifier().index);
checkBindingIsNotSpecified(field.line(), field.type()->getLayoutQualifier().binding); checkBindingIsNotSpecified(field.line(), field.type()->getLayoutQualifier().binding);
checkLocationIsNotSpecified(field.line(), field.type()->getLayoutQualifier()); checkLocationIsNotSpecified(field.line(), field.type()->getLayoutQualifier());
......
...@@ -373,6 +373,10 @@ class TParseContext : angle::NonCopyable ...@@ -373,6 +373,10 @@ class TParseContext : angle::NonCopyable
const TSourceLoc &intValueLine, const TSourceLoc &intValueLine,
const std::string &intValueString, const std::string &intValueString,
int *numMaxVertices); int *numMaxVertices);
void parseIndexLayoutQualifier(int intValue,
const TSourceLoc &intValueLine,
const std::string &intValueString,
int *index);
TLayoutQualifier parseLayoutQualifier(const ImmutableString &qualifierType, TLayoutQualifier parseLayoutQualifier(const ImmutableString &qualifierType,
const TSourceLoc &qualifierTypeLine); const TSourceLoc &qualifierTypeLine);
TLayoutQualifier parseLayoutQualifier(const ImmutableString &qualifierType, TLayoutQualifier parseLayoutQualifier(const ImmutableString &qualifierType,
...@@ -511,6 +515,7 @@ class TParseContext : angle::NonCopyable ...@@ -511,6 +515,7 @@ class TParseContext : angle::NonCopyable
void checkAtomicCounterOffsetDoesNotOverlap(bool forceAppend, void checkAtomicCounterOffsetDoesNotOverlap(bool forceAppend,
const TSourceLoc &loc, const TSourceLoc &loc,
TType *type); TType *type);
void checkIndexIsNotSpecified(const TSourceLoc &location, int index);
void checkBindingIsValid(const TSourceLoc &identifierLocation, const TType &type); void checkBindingIsValid(const TSourceLoc &identifierLocation, const TType &type);
void checkBindingIsNotSpecified(const TSourceLoc &location, int binding); void checkBindingIsNotSpecified(const TSourceLoc &location, int binding);
void checkOffsetIsNotSpecified(const TSourceLoc &location, int offset); void checkOffsetIsNotSpecified(const TSourceLoc &location, int offset);
......
...@@ -682,6 +682,17 @@ TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier, ...@@ -682,6 +682,17 @@ TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier,
joinedQualifier.maxVertices = rightQualifier.maxVertices; joinedQualifier.maxVertices = rightQualifier.maxVertices;
} }
if (rightQualifier.index != -1)
{
if (joinedQualifier.index != -1)
{
// EXT_blend_func_extended spec: "Each of these qualifiers may appear at most once"
diagnostics->error(rightQualifierLocation, "Cannot have multiple index specifiers",
"index");
}
joinedQualifier.index = rightQualifier.index;
}
return joinedQualifier; return joinedQualifier;
} }
......
...@@ -352,7 +352,7 @@ bool Attribute::operator==(const Attribute &other) const ...@@ -352,7 +352,7 @@ bool Attribute::operator==(const Attribute &other) const
return VariableWithLocation::operator==(other); return VariableWithLocation::operator==(other);
} }
OutputVariable::OutputVariable() OutputVariable::OutputVariable() : index(-1)
{ {
} }
...@@ -360,19 +360,12 @@ OutputVariable::~OutputVariable() ...@@ -360,19 +360,12 @@ OutputVariable::~OutputVariable()
{ {
} }
OutputVariable::OutputVariable(const OutputVariable &other) : VariableWithLocation(other) OutputVariable::OutputVariable(const OutputVariable &other) = default;
{ OutputVariable &OutputVariable::operator=(const OutputVariable &other) = default;
}
OutputVariable &OutputVariable::operator=(const OutputVariable &other)
{
VariableWithLocation::operator=(other);
return *this;
}
bool OutputVariable::operator==(const OutputVariable &other) const bool OutputVariable::operator==(const OutputVariable &other) const
{ {
return VariableWithLocation::operator==(other); return VariableWithLocation::operator==(other) && index == other.index;
} }
InterfaceBlockField::InterfaceBlockField() : isRowMajorLayout(false) InterfaceBlockField::InterfaceBlockField() : isRowMajorLayout(false)
......
...@@ -92,7 +92,8 @@ void ValidateOutputsTraverser::visitSymbol(TIntermSymbol *symbol) ...@@ -92,7 +92,8 @@ void ValidateOutputsTraverser::visitSymbol(TIntermSymbol *symbol)
void ValidateOutputsTraverser::validate(TDiagnostics *diagnostics) const void ValidateOutputsTraverser::validate(TDiagnostics *diagnostics) const
{ {
ASSERT(diagnostics); ASSERT(diagnostics);
OutputVector validOutputs(mMaxDrawBuffers); OutputVector validOutputs(mMaxDrawBuffers, nullptr);
OutputVector validSecondaryOutputs(mMaxDrawBuffers, nullptr);
for (const auto &symbol : mOutputs) for (const auto &symbol : mOutputs)
{ {
...@@ -104,21 +105,29 @@ void ValidateOutputsTraverser::validate(TDiagnostics *diagnostics) const ...@@ -104,21 +105,29 @@ void ValidateOutputsTraverser::validate(TDiagnostics *diagnostics) const
ASSERT(type.getLayoutQualifier().location != -1); ASSERT(type.getLayoutQualifier().location != -1);
if (location + elementCount <= validOutputs.size()) OutputVector &validOutputsToUse = validOutputs;
// The default index is 0, so we only assign the output to secondary outputs in case the
// index is explicitly set to 1.
if (type.getLayoutQualifier().index == 1)
{
validOutputsToUse = validSecondaryOutputs;
}
if (location + elementCount <= validOutputsToUse.size())
{ {
for (size_t elementIndex = 0; elementIndex < elementCount; elementIndex++) for (size_t elementIndex = 0; elementIndex < elementCount; elementIndex++)
{ {
const size_t offsetLocation = location + elementIndex; const size_t offsetLocation = location + elementIndex;
if (validOutputs[offsetLocation]) if (validOutputsToUse[offsetLocation])
{ {
std::stringstream strstr; std::stringstream strstr;
strstr << "conflicting output locations with previously defined output '" strstr << "conflicting output locations with previously defined output '"
<< validOutputs[offsetLocation]->getName() << "'"; << validOutputsToUse[offsetLocation]->getName() << "'";
error(*symbol, strstr.str().c_str(), diagnostics); error(*symbol, strstr.str().c_str(), diagnostics);
} }
else else
{ {
validOutputs[offsetLocation] = symbol; validOutputsToUse[offsetLocation] = symbol;
} }
} }
} }
......
...@@ -363,6 +363,7 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context, ...@@ -363,6 +363,7 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context,
sh::OutputVariable output; sh::OutputVariable output;
LoadShaderVar(&stream, &output); LoadShaderVar(&stream, &output);
output.location = stream.readInt<int>(); output.location = stream.readInt<int>();
output.index = stream.readInt<int>();
state->mOutputVariables.push_back(output); state->mOutputVariables.push_back(output);
} }
...@@ -555,6 +556,7 @@ void MemoryProgramCache::Serialize(const Context *context, ...@@ -555,6 +556,7 @@ void MemoryProgramCache::Serialize(const Context *context,
{ {
WriteShaderVar(&stream, output); WriteShaderVar(&stream, output);
stream.writeInt(output.location); stream.writeInt(output.location);
stream.writeInt(output.index);
} }
stream.writeInt(state.getOutputLocations().size()); stream.writeInt(state.getOutputLocations().size());
......
...@@ -40,6 +40,8 @@ class CollectVariablesTest : public testing::Test ...@@ -40,6 +40,8 @@ class CollectVariablesTest : public testing::Test
ShBuiltInResources resources; ShBuiltInResources resources;
InitBuiltInResources(&resources); InitBuiltInResources(&resources);
resources.MaxDrawBuffers = 8; resources.MaxDrawBuffers = 8;
resources.EXT_blend_func_extended = true;
resources.MaxDualSourceDrawBuffers = 1;
initTranslator(resources); initTranslator(resources);
} }
...@@ -2058,3 +2060,29 @@ TEST_F(CollectVertexVariablesTest, VaryingOnlyDeclaredInvariant) ...@@ -2058,3 +2060,29 @@ TEST_F(CollectVertexVariablesTest, VaryingOnlyDeclaredInvariant)
EXPECT_FALSE(varying.staticUse); EXPECT_FALSE(varying.staticUse);
EXPECT_FALSE(varying.active); EXPECT_FALSE(varying.active);
} }
// Test an output variable that is declared with the index layout qualifier from
// EXT_blend_func_extended.
TEST_F(CollectFragmentVariablesTest, OutputVarESSL3EXTBlendFuncExtendedIndex)
{
const std::string &shaderString =
R"(#version 300 es
#extension GL_EXT_blend_func_extended : require
precision mediump float;
layout(location = 0, index = 1) out float outVar;
void main()
{
outVar = 0.0;
})";
compile(shaderString);
const auto &outputs = mTranslator->getOutputVariables();
ASSERT_EQ(1u, outputs.size());
const OutputVariable &output = outputs[0];
EXPECT_EQ("outVar", output.name);
EXPECT_TRUE(output.staticUse);
EXPECT_TRUE(output.active);
EXPECT_EQ(1, output.index);
}
...@@ -67,9 +67,8 @@ const char ESSL300_MaxDualSourceAccessShader[] = ...@@ -67,9 +67,8 @@ const char ESSL300_MaxDualSourceAccessShader[] =
" fragColor = vec4(gl_MaxDualSourceDrawBuffersEXT / 10);\n" " fragColor = vec4(gl_MaxDualSourceDrawBuffersEXT / 10);\n"
"}\n"; "}\n";
// In GLSL version 300 es, the only way to write a correct shader is to require the extension and // In ES 3.0, the locations can be assigned through the API with glBindFragDataLocationIndexedEXT.
// then leave the locations unspecified. The caller will then bind the variables with the extension // It's fine to have a mix of specified and unspecified locations.
// binding functions.
const char ESSL300_LocationAndUnspecifiedOutputShader[] = const char ESSL300_LocationAndUnspecifiedOutputShader[] =
"precision mediump float;\n" "precision mediump float;\n"
"layout(location = 0) out mediump vec4 fragColor;" "layout(location = 0) out mediump vec4 fragColor;"
...@@ -79,6 +78,7 @@ const char ESSL300_LocationAndUnspecifiedOutputShader[] = ...@@ -79,6 +78,7 @@ const char ESSL300_LocationAndUnspecifiedOutputShader[] =
" secondaryFragColor = vec4(1.0);\n" " secondaryFragColor = vec4(1.0);\n"
"}\n"; "}\n";
// It's also fine to leave locations completely unspecified.
const char ESSL300_TwoUnspecifiedLocationOutputsShader[] = const char ESSL300_TwoUnspecifiedLocationOutputsShader[] =
"precision mediump float;\n" "precision mediump float;\n"
"out mediump vec4 fragColor;" "out mediump vec4 fragColor;"
...@@ -88,26 +88,71 @@ const char ESSL300_TwoUnspecifiedLocationOutputsShader[] = ...@@ -88,26 +88,71 @@ const char ESSL300_TwoUnspecifiedLocationOutputsShader[] =
" secondaryFragColor = vec4(1.0);\n" " secondaryFragColor = vec4(1.0);\n"
"}\n"; "}\n";
// Shader that is correct in GLSL ES 3.10 fails when used in version 300 es. // Shader that is specifies two outputs with the same location but different indexes is valid.
const char ESSL310_LocationIndexShader[] = const char ESSL300_LocationIndexShader[] =
"precision mediump float;\n" R"(precision mediump float;
"layout(location = 0) out mediump vec4 fragColor;" layout(location = 0) out mediump vec4 fragColor;
"layout(location = 0, index = 1) out mediump vec4 secondaryFragColor;" layout(location = 0, index = 1) out mediump vec4 secondaryFragColor;
"void main() {\n" void main() {
" fragColor = vec4(1);\n" fragColor = vec4(1);
" secondaryFragColor = vec4(1);\n" secondaryFragColor = vec4(1);
"}\n"; })";
// Shader that specifies index layout qualifier but not location fails to compile. Currently fails // Shader that specifies index layout qualifier but not location fails to compile.
// to compile due to version 310 es not being supported. const char ESSL300_LocationIndexFailureShader[] =
const char ESSL310_LocationIndexFailureShader[] = R"(precision mediump float;
"precision mediump float;\n" layout(index = 0) out vec4 fragColor;
"layout(location = 0) out mediump vec4 fragColor;" void main() {
"layout(index = 1) out mediump vec4 secondaryFragColor;" fragColor = vec4(1.0);
"void main() {\n" })";
" fragColor = vec4(1.0);\n"
" secondaryFragColor = vec4(1.0);\n" // Shader that specifies index layout qualifier multiple times fails to compile.
"}\n"; const char ESSL300_DoubleIndexFailureShader[] =
R"(precision mediump float;
layout(index = 0, location = 0, index = 1) out vec4 fragColor;
void main() {
fragColor = vec4(1.0);
})";
// Global index layout qualifier fails.
const char ESSL300_GlobalIndexFailureShader[] =
R"(precision mediump float;
layout(index = 0);
out vec4 fragColor;
void main() {
fragColor = vec4(1.0);
})";
// Index layout qualifier on a non-output variable fails.
const char ESSL300_IndexOnUniformVariableFailureShader[] =
R"(precision mediump float;
layout(index = 0) uniform vec4 u;
out vec4 fragColor;
void main() {
fragColor = u;
})";
// Index layout qualifier on a struct fails.
const char ESSL300_IndexOnStructFailureShader[] =
R"(precision mediump float;
layout(index = 0) struct S {
vec4 field;
};
out vec4 fragColor;
void main() {
fragColor = vec4(1.0);
})";
// Index layout qualifier on a struct member fails.
const char ESSL300_IndexOnStructFieldFailureShader[] =
R"(precision mediump float;
struct S {
layout(index = 0) vec4 field;
};
out mediump vec4 fragColor;
void main() {
fragColor = vec4(1.0);
})";
class EXTBlendFuncExtendedTest : public sh::ShaderExtensionTest class EXTBlendFuncExtendedTest : public sh::ShaderExtensionTest
{ {
...@@ -169,7 +214,8 @@ INSTANTIATE_TEST_CASE_P(CorrectESSL300Shaders, ...@@ -169,7 +214,8 @@ INSTANTIATE_TEST_CASE_P(CorrectESSL300Shaders,
Values(sh::ESSLVersion300), Values(sh::ESSLVersion300),
Values(ESSL300_MaxDualSourceAccessShader, Values(ESSL300_MaxDualSourceAccessShader,
ESSL300_LocationAndUnspecifiedOutputShader, ESSL300_LocationAndUnspecifiedOutputShader,
ESSL300_TwoUnspecifiedLocationOutputsShader))); ESSL300_TwoUnspecifiedLocationOutputsShader,
ESSL300_LocationIndexShader)));
class EXTBlendFuncExtendedCompileFailureTest : public EXTBlendFuncExtendedTest class EXTBlendFuncExtendedCompileFailureTest : public EXTBlendFuncExtendedTest
{ {
...@@ -208,23 +254,16 @@ INSTANTIATE_TEST_CASE_P(CorrectESSL100Shaders, ...@@ -208,23 +254,16 @@ INSTANTIATE_TEST_CASE_P(CorrectESSL100Shaders,
Values(sh::ESSLVersion300), Values(sh::ESSLVersion300),
Values(ESSL100_SimpleShader1, ESSL100_FragDataShader))); Values(ESSL100_SimpleShader1, ESSL100_FragDataShader)));
// Incorrect #version 310 es always fails. // Incorrect #version 300 es shaders always fail.
INSTANTIATE_TEST_CASE_P(IncorrectESSL310Shaders, INSTANTIATE_TEST_CASE_P(IncorrectESSL300Shaders,
EXTBlendFuncExtendedCompileFailureTest, EXTBlendFuncExtendedCompileFailureTest,
Combine(Values(SH_GLES3_SPEC), Combine(Values(SH_GLES3_1_SPEC),
Values(sh::ESSLVersion300, sh::ESSLVersion310), Values(sh::ESSLVersion300, sh::ESSLVersion310),
Values(ESSL310_LocationIndexFailureShader))); Values(ESSL300_LocationIndexFailureShader,
ESSL300_DoubleIndexFailureShader,
// Correct #version 310 es fails in #version 300 es. ESSL300_GlobalIndexFailureShader,
INSTANTIATE_TEST_CASE_P( ESSL300_IndexOnUniformVariableFailureShader,
CorrectESSL310ShadersInESSL300, ESSL300_IndexOnStructFailureShader,
EXTBlendFuncExtendedCompileFailureTest, ESSL300_IndexOnStructFieldFailureShader)));
Values(make_tuple(SH_GLES3_SPEC, &sh::ESSLVersion300[0], &ESSL310_LocationIndexShader[0])));
// Correct #version 310 es fails in #version 310 es, due to 3.1 not being supported.
INSTANTIATE_TEST_CASE_P(
CorrectESSL310Shaders,
EXTBlendFuncExtendedCompileFailureTest,
Values(make_tuple(SH_GLES3_SPEC, &sh::ESSLVersion310[0], &ESSL310_LocationIndexShader[0])));
} // namespace } // namespace
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