translator: Reject shaders that use both FragColor+FragData.
We checked this at link time in the D3D back-end, but this
restriction applies to all shaders.
TEST=dEQP-GLES2.functional.shaders.fragdata.*
BUG=angleproject:995
BUG=478572
Change-Id: I99111cc6aa05b9352693f9c3b5bc70d56c9842d4
Reviewed-on: https://chromium-review.googlesource.com/269846
Reviewed-by: Zhenyao Mo <zmo@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index 784032d..a9e9516 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -1049,6 +1049,27 @@
{
recover();
}
+
+ // Reject shaders using both gl_FragData and gl_FragColor
+ TQualifier qualifier = variable->getType().getQualifier();
+ if (qualifier == EvqFragData)
+ {
+ mUsesFragData = true;
+ }
+ else if (qualifier == EvqFragColor)
+ {
+ mUsesFragColor = true;
+ }
+
+ // This validation is not quite correct - it's only an error to write to
+ // both FragData and FragColor. For simplicity, and because users shouldn't
+ // be rewarded for reading from undefined varaibles, return an error
+ // if they are both referenced, rather than assigned.
+ if (mUsesFragData && mUsesFragColor)
+ {
+ error(location, "cannot use both gl_FragData and gl_FragColor", name->c_str());
+ recover();
+ }
}
if (!variable)
diff --git a/src/compiler/translator/ParseContext.h b/src/compiler/translator/ParseContext.h
index d328e9a..1c37e1a 100644
--- a/src/compiler/translator/ParseContext.h
+++ b/src/compiler/translator/ParseContext.h
@@ -57,7 +57,9 @@
mDirectiveHandler(ext, mDiagnostics, mShaderVersion, debugShaderPrecisionSupported),
mPreprocessor(&mDiagnostics, &mDirectiveHandler),
mScanner(nullptr),
- mDeferredSingleDeclarationErrorCheck(false)
+ mDeferredSingleDeclarationErrorCheck(false),
+ mUsesFragData(false),
+ mUsesFragColor(false)
{
}
@@ -74,6 +76,7 @@
const char *extraInfo="");
void warning(const TSourceLoc &loc, const char *reason, const char *token,
const char *extraInfo="");
+
void recover();
TIntermNode *getTreeRoot() const { return mTreeRoot; }
void setTreeRoot(TIntermNode *treeRoot) { mTreeRoot = treeRoot; }
@@ -341,6 +344,8 @@
TDirectiveHandler mDirectiveHandler;
pp::Preprocessor mPreprocessor;
void *mScanner;
+ bool mUsesFragData; // track if we are using both gl_FragData and gl_FragColor
+ bool mUsesFragColor;
};
int PaParseStrings(
diff --git a/src/libANGLE/renderer/d3d/DynamicHLSL.cpp b/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
index b2c24d0..beb6685 100644
--- a/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
+++ b/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
@@ -757,11 +757,8 @@
bool usesPointSize = vertexShader->mUsesPointSize;
bool useInstancedPointSpriteEmulation = usesPointSize && mRenderer->getWorkarounds().useInstancedPointSpriteEmulation;
- if (usesFragColor && usesFragData)
- {
- infoLog << "Cannot use both gl_FragColor and gl_FragData in the same fragment shader.";
- return false;
- }
+ // Validation done in the compiler
+ ASSERT(!usesFragColor || !usesFragData);
// Write the HLSL input/output declarations
const int shaderModel = mRenderer->getMajorShaderModel();
diff --git a/src/tests/compiler_tests/MalformedShader_test.cpp b/src/tests/compiler_tests/MalformedShader_test.cpp
index f5fa4e9..a49167ad 100644
--- a/src/tests/compiler_tests/MalformedShader_test.cpp
+++ b/src/tests/compiler_tests/MalformedShader_test.cpp
@@ -545,3 +545,20 @@
FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
}
}
+
+// Statically assigning to both gl_FragData and gl_FragColor is forbidden (ESSL 1.00 section 7.2)
+TEST_F(MalformedShaderTest, WriteBothFragDataAndFragColor)
+{
+ const std::string &shaderString =
+ "precision mediump float;\n"
+ "void foo() {\n"
+ " gl_FragData[0].a++;\n"
+ "}\n"
+ "void main() {\n"
+ " gl_FragColor.x += 0.0;\n"
+ "}\n";
+ if (compile(shaderString))
+ {
+ FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
+ }
+}