Commit 817232ef by Yuly Novikov Committed by Commit Bot

Validate invariance of built-in variables when linking

According to ESSL 1.00.17 paragraph 4.6.4 BUG=angleproject:1876 Change-Id: I61e142c31dce11eec28fe240a9bc9ce2c632daf6 Reviewed-on: https://chromium-review.googlesource.com/446870Reviewed-by: 's avatarKenneth Russell <kbr@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Yuly Novikov <ynovikov@chromium.org>
parent 010e4dbd
...@@ -407,9 +407,6 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[], ...@@ -407,9 +407,6 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
(outputType == SH_GLSL_COMPATIBILITY_OUTPUT))) (outputType == SH_GLSL_COMPATIBILITY_OUTPUT)))
initializeGLPosition(root); initializeGLPosition(root);
if (success && RemoveInvariant(shaderType, shaderVersion, outputType, compileOptions))
sh::RemoveInvariantDeclaration(root);
// This pass might emit short circuits so keep it before the short circuit unfolding // This pass might emit short circuits so keep it before the short circuit unfolding
if (success && (compileOptions & SH_REWRITE_DO_WHILE_LOOPS)) if (success && (compileOptions & SH_REWRITE_DO_WHILE_LOOPS))
RewriteDoWhile(root, getTemporaryIndex()); RewriteDoWhile(root, getTemporaryIndex());
...@@ -450,6 +447,11 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[], ...@@ -450,6 +447,11 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
} }
} }
// Removing invariant declarations must be done after collecting variables.
// Otherwise, built-in invariant declarations don't apply.
if (success && RemoveInvariant(shaderType, shaderVersion, outputType, compileOptions))
sh::RemoveInvariantDeclaration(root);
if (success && (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS)) if (success && (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS))
{ {
ScalarizeVecAndMatConstructorArgs(root, shaderType, fragmentPrecisionHigh, ScalarizeVecAndMatConstructorArgs(root, shaderType, fragmentPrecisionHigh,
......
...@@ -1917,6 +1917,11 @@ bool Program::linkVaryings(InfoLog &infoLog) const ...@@ -1917,6 +1917,11 @@ bool Program::linkVaryings(InfoLog &infoLog) const
} }
} }
if (!linkValidateBuiltInVaryings(infoLog))
{
return false;
}
// TODO(jmadill): verify no unmatched vertex varyings? // TODO(jmadill): verify no unmatched vertex varyings?
return true; return true;
...@@ -2445,6 +2450,77 @@ bool Program::linkValidateVaryings(InfoLog &infoLog, ...@@ -2445,6 +2450,77 @@ bool Program::linkValidateVaryings(InfoLog &infoLog,
return true; return true;
} }
bool Program::linkValidateBuiltInVaryings(InfoLog &infoLog) const
{
const Shader *vertexShader = mState.mAttachedVertexShader;
const Shader *fragmentShader = mState.mAttachedFragmentShader;
const std::vector<sh::Varying> &vertexVaryings = vertexShader->getVaryings();
const std::vector<sh::Varying> &fragmentVaryings = fragmentShader->getVaryings();
int shaderVersion = vertexShader->getShaderVersion();
if (shaderVersion != 100)
{
// Only ESSL 1.0 has restrictions on matching input and output invariance
return true;
}
bool glPositionIsInvariant = false;
bool glPointSizeIsInvariant = false;
bool glFragCoordIsInvariant = false;
bool glPointCoordIsInvariant = false;
for (const sh::Varying &varying : vertexVaryings)
{
if (!varying.isBuiltIn())
{
continue;
}
if (varying.name.compare("gl_Position") == 0)
{
glPositionIsInvariant = varying.isInvariant;
}
else if (varying.name.compare("gl_PointSize") == 0)
{
glPointSizeIsInvariant = varying.isInvariant;
}
}
for (const sh::Varying &varying : fragmentVaryings)
{
if (!varying.isBuiltIn())
{
continue;
}
if (varying.name.compare("gl_FragCoord") == 0)
{
glFragCoordIsInvariant = varying.isInvariant;
}
else if (varying.name.compare("gl_PointCoord") == 0)
{
glPointCoordIsInvariant = varying.isInvariant;
}
}
// There is some ambiguity in ESSL 1.00.17 paragraph 4.6.4 interpretation,
// for example, https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13842.
// Not requiring invariance to match is supported by:
// dEQP, WebGL CTS, Nexus 5X GLES
if (glFragCoordIsInvariant && !glPositionIsInvariant)
{
infoLog << "gl_FragCoord can only be declared invariant if and only if gl_Position is "
"declared invariant.";
return false;
}
if (glPointCoordIsInvariant && !glPointSizeIsInvariant)
{
infoLog << "gl_PointCoord can only be declared invariant if and only if gl_PointSize is "
"declared invariant.";
return false;
}
return true;
}
bool Program::linkValidateTransformFeedback(InfoLog &infoLog, bool Program::linkValidateTransformFeedback(InfoLog &infoLog,
const Program::MergedVaryings &varyings, const Program::MergedVaryings &varyings,
const Caps &caps) const const Caps &caps) const
......
...@@ -464,6 +464,7 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -464,6 +464,7 @@ class Program final : angle::NonCopyable, public LabeledObject
const sh::Varying &vertexVarying, const sh::Varying &vertexVarying,
const sh::Varying &fragmentVarying, const sh::Varying &fragmentVarying,
int shaderVersion); int shaderVersion);
bool linkValidateBuiltInVaryings(InfoLog &infoLog) const;
bool linkValidateTransformFeedback(InfoLog &infoLog, bool linkValidateTransformFeedback(InfoLog &infoLog,
const MergedVaryings &linkedVaryings, const MergedVaryings &linkedVaryings,
const Caps &caps) const; const Caps &caps) const;
......
...@@ -929,6 +929,37 @@ void WebGLCompatibilityTest::drawBuffersFeedbackLoop(GLuint program, ...@@ -929,6 +929,37 @@ void WebGLCompatibilityTest::drawBuffersFeedbackLoop(GLuint program,
EXPECT_GL_ERROR(expectedError); EXPECT_GL_ERROR(expectedError);
} }
// Tests invariance matching rules between built in varyings.
// Based on WebGL test conformance/glsl/misc/shaders-with-invariance.html.
TEST_P(WebGLCompatibilityTest, BuiltInInvariant)
{
const std::string vertexShaderVariant =
"varying vec4 v_varying;\n"
"void main()\n"
"{\n"
" gl_PointSize = 1.0;\n"
" gl_Position = v_varying;\n"
"}";
const std::string fragmentShaderInvariantGlFragCoord =
"invariant gl_FragCoord;\n"
"void main()\n"
"{\n"
" gl_FragColor = gl_FragCoord;\n"
"}";
const std::string fragmentShaderInvariantGlPointCoord =
"invariant gl_PointCoord;\n"
"void main()\n"
"{\n"
" gl_FragColor = vec4(gl_PointCoord, 0.0, 0.0);\n"
"}";
GLuint program = CompileProgram(vertexShaderVariant, fragmentShaderInvariantGlFragCoord);
EXPECT_EQ(0u, program);
program = CompileProgram(vertexShaderVariant, fragmentShaderInvariantGlPointCoord);
EXPECT_EQ(0u, program);
}
// This tests that rendering feedback loops works as expected with WebGL 2. // This tests that rendering feedback loops works as expected with WebGL 2.
// Based on WebGL test conformance2/rendering/rendering-sampling-feedback-loop.html // Based on WebGL test conformance2/rendering/rendering-sampling-feedback-loop.html
TEST_P(WebGL2CompatibilityTest, RenderingFeedbackLoopWithDrawBuffers) TEST_P(WebGL2CompatibilityTest, RenderingFeedbackLoopWithDrawBuffers)
......
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