Commit 3e960463 by Olli Etuaho

Detect when gl_FragData is indexed with != 0 in WebGL 2.0

WebGL 2.0 explicitly specifies it to be an error when gl_FragData is indexed with anything else than constant zero in spec section 'GLSL ES 1.00 Fragment Shader Output'. This doesn't apply to WebGL 1.0 or GLES. dEQP-GLES2.functional.shaders.fragdata* test that dynamic indexing of gl_FragData is allowed. TEST=angle_unittests BUG=angleproject:1210 Change-Id: Ib401242e7867f5e7943456b059dd8e24dc404098 Reviewed-on: https://chromium-review.googlesource.com/312045Tested-by: 's avatarOlli Etuaho <oetuaho@nvidia.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent bd163f6a
...@@ -2724,6 +2724,11 @@ TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression, ...@@ -2724,6 +2724,11 @@ TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression,
"array indexes for fragment outputs must be constant integral expressions"); "array indexes for fragment outputs must be constant integral expressions");
recover(); recover();
} }
else if (mShaderSpec == SH_WEBGL2_SPEC && baseExpression->getQualifier() == EvqFragData)
{
error(location, "", "[", "array index for gl_FragData must be constant zero");
recover();
}
} }
if (indexConstantUnion) if (indexConstantUnion)
...@@ -2775,7 +2780,29 @@ TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression, ...@@ -2775,7 +2780,29 @@ TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression,
if (baseExpression->isArray()) if (baseExpression->isArray())
{ {
if (index >= baseExpression->getType().getArraySize()) if (baseExpression->getQualifier() == EvqFragData && index > 0)
{
if (mShaderSpec == SH_WEBGL2_SPEC)
{
// Error has been already generated if index is not const.
if (indexExpression->getQualifier() == EvqConst)
{
error(location, "", "[",
"array index for gl_FragData must be constant zero");
recover();
}
safeIndex = 0;
}
else if (!isExtensionEnabled("GL_EXT_draw_buffers"))
{
outOfRangeError(outOfRangeIndexIsError, location, "", "[",
"array index for gl_FragData must be zero when "
"GL_EXT_draw_buffers is disabled");
safeIndex = 0;
}
}
// Only do generic out-of-range check if similar error hasn't already been reported.
if (safeIndex < 0 && index >= baseExpression->getType().getArraySize())
{ {
std::stringstream extraInfoStream; std::stringstream extraInfoStream;
extraInfoStream << "array index out of range '" << index << "'"; extraInfoStream << "array index out of range '" << index << "'";
...@@ -2783,15 +2810,6 @@ TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression, ...@@ -2783,15 +2810,6 @@ TIntermTyped *TParseContext::addIndexExpression(TIntermTyped *baseExpression,
outOfRangeError(outOfRangeIndexIsError, location, "", "[", extraInfo.c_str()); outOfRangeError(outOfRangeIndexIsError, location, "", "[", extraInfo.c_str());
safeIndex = baseExpression->getType().getArraySize() - 1; safeIndex = baseExpression->getType().getArraySize() - 1;
} }
else if (baseExpression->getQualifier() == EvqFragData && index > 0 &&
!isExtensionEnabled("GL_EXT_draw_buffers"))
{
outOfRangeError(
outOfRangeIndexIsError, location, "", "[",
"array indexes for gl_FragData must be zero when GL_EXT_draw_buffers is "
"disabled");
safeIndex = 0;
}
} }
else if ((baseExpression->isVector() || baseExpression->isMatrix()) && else if ((baseExpression->isVector() || baseExpression->isMatrix()) &&
baseExpression->getType().getNominalSize() <= index) baseExpression->getType().getNominalSize() <= index)
......
...@@ -68,6 +68,22 @@ class MalformedVertexShaderTest : public MalformedShaderTest ...@@ -68,6 +68,22 @@ class MalformedVertexShaderTest : public MalformedShaderTest
} }
}; };
class MalformedWebGL2ShaderTest : public MalformedShaderTest
{
public:
MalformedWebGL2ShaderTest() {}
protected:
void SetUp() override
{
ShBuiltInResources resources;
ShInitBuiltInResources(&resources);
mTranslator = new TranslatorESSL(GL_FRAGMENT_SHADER, SH_WEBGL2_SPEC);
ASSERT_TRUE(mTranslator->Init(resources));
}
};
// This is a test for a bug that used to exist in ANGLE: // This is a test for a bug that used to exist in ANGLE:
// Calling a function with all parameters missing should not succeed. // Calling a function with all parameters missing should not succeed.
TEST_F(MalformedShaderTest, FunctionParameterMismatch) TEST_F(MalformedShaderTest, FunctionParameterMismatch)
...@@ -1218,3 +1234,22 @@ TEST_F(MalformedShaderTest, StructConstructorWithStructDefinition) ...@@ -1218,3 +1234,22 @@ TEST_F(MalformedShaderTest, StructConstructorWithStructDefinition)
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog; FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
} }
} }
// Test that indexing gl_FragData with a non-constant expression is forbidden in WebGL 2.0, even
// when ANGLE is able to constant fold the index.
// WebGL 2.0 spec section 'GLSL ES 1.00 Fragment Shader Output'
TEST_F(MalformedWebGL2ShaderTest, IndexFragDataWithNonConstant)
{
const std::string &shaderString =
"precision mediump float;\n"
"void main()\n"
"{\n"
" for (int i = 0; i < 2; ++i) {\n"
" gl_FragData[true ? 0 : i] = vec4(0.0);\n"
" }\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << 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