Commit 0d88ec9f by Jiawei Shao Committed by Commit Bot

ES31: Add link validations on geometry shader uniforms

This patch adds the link validations on the uniforms defined in a geometry shader. 1. Validate if there is any link mismatch between a geometry shader uniform and a uniform defined in another shader in the current graphics pipeline. 2. Validate if the number of images, samplers or atomic counters in a geometry shader exceeds the related resource limit. 3. Validate if there is name contradiction between a geometry shader uniform and a vertex shader attribute. BUG=angleproject:1941 TEST=dEQP-GLES31.functional.shaders.linkage.es31.geometry.uniform.* dEQP-GLES31.functional.geometry_shading.basic.* dEQP-GLES31.functional.geometry_shading.conversion.* dEQP-GLES31.functional.geometry_shading.emit.* dEQP-GLES31.functional.geometry_shading.varying.* dEQP-GLES31.functional.geometry_shading.instanced.geometry_* dEQP-GLES31.functional.geometry_shading.instanced.invocation_output_* dEQP-GLES31.functional.geometry_shading.instanced.draw_* Change-Id: I365aee624a3a79658c3e4c7487a586cf9532b529 Reviewed-on: https://chromium-review.googlesource.com/939264 Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 888081d5
......@@ -67,6 +67,7 @@ void WriteShaderVariableBuffer(BinaryOutputStream *stream, const ShaderVariableB
stream->writeInt(var.vertexStaticUse);
stream->writeInt(var.fragmentStaticUse);
stream->writeInt(var.computeStaticUse);
stream->writeInt(var.geometryStaticUse);
stream->writeInt(var.memberIndexes.size());
for (unsigned int memberCounterIndex : var.memberIndexes)
......@@ -82,6 +83,7 @@ void LoadShaderVariableBuffer(BinaryInputStream *stream, ShaderVariableBuffer *v
var->vertexStaticUse = stream->readBool();
var->fragmentStaticUse = stream->readBool();
var->computeStaticUse = stream->readBool();
var->geometryStaticUse = stream->readBool();
unsigned int numMembers = stream->readInt<unsigned int>();
for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
......
......@@ -2466,7 +2466,7 @@ bool Program::linkAtomicCounterBuffers()
}
}
// TODO(jie.a.chen@intel.com): Count each atomic counter buffer to validate against
// gl_Max[Vertex|Fragment|Compute|Combined]AtomicCounterBuffers.
// gl_Max[Vertex|Fragment|Compute|Geometry|Combined]AtomicCounterBuffers.
return true;
}
......@@ -3108,6 +3108,9 @@ bool Program::linkValidateGlobalNames(const Context *context, InfoLog &infoLog)
mState.mAttachedVertexShader->getUniforms(context);
const std::vector<sh::Uniform> &fragmentUniforms =
mState.mAttachedFragmentShader->getUniforms(context);
const std::vector<sh::Uniform> *geometryUniforms =
(mState.mAttachedGeometryShader) ? &mState.mAttachedGeometryShader->getUniforms(context)
: nullptr;
const std::vector<sh::Attribute> &attributes =
mState.mAttachedVertexShader->getActiveAttributes(context);
for (const auto &attrib : attributes)
......@@ -3128,6 +3131,17 @@ bool Program::linkValidateGlobalNames(const Context *context, InfoLog &infoLog)
return false;
}
}
if (geometryUniforms)
{
for (const auto &uniform : *geometryUniforms)
{
if (uniform.name == attrib.name)
{
infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
return false;
}
}
}
}
return true;
}
......
......@@ -64,6 +64,80 @@ void SetStaticUse(std::vector<VarT> *list,
}
}
// GLSL ES Spec 3.00.3, section 4.3.5.
LinkMismatchError LinkValidateUniforms(const sh::Uniform &uniform1,
const sh::Uniform &uniform2,
std::string *mismatchedStructFieldName)
{
#if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED
const bool validatePrecision = true;
#else
const bool validatePrecision = false;
#endif
LinkMismatchError linkError = Program::LinkValidateVariablesBase(
uniform1, uniform2, validatePrecision, true, mismatchedStructFieldName);
if (linkError != LinkMismatchError::NO_MISMATCH)
{
return linkError;
}
// GLSL ES Spec 3.10.4, section 4.4.5.
if (uniform1.binding != -1 && uniform2.binding != -1 && uniform1.binding != uniform2.binding)
{
return LinkMismatchError::BINDING_MISMATCH;
}
// GLSL ES Spec 3.10.4, section 9.2.1.
if (uniform1.location != -1 && uniform2.location != -1 &&
uniform1.location != uniform2.location)
{
return LinkMismatchError::LOCATION_MISMATCH;
}
if (uniform1.offset != uniform2.offset)
{
return LinkMismatchError::OFFSET_MISMATCH;
}
return LinkMismatchError::NO_MISMATCH;
}
using ShaderUniform = std::pair<GLenum, const sh::Uniform *>;
bool ValidateGraphicsUniformsPerShader(const Context *context,
Shader *shaderToLink,
bool extendLinkedUniforms,
std::map<std::string, ShaderUniform> *linkedUniforms,
InfoLog &infoLog)
{
ASSERT(context && shaderToLink && linkedUniforms);
for (const sh::Uniform &uniform : shaderToLink->getUniforms(context))
{
const auto &entry = linkedUniforms->find(uniform.name);
if (entry != linkedUniforms->end())
{
const sh::Uniform &linkedUniform = *(entry->second.second);
std::string mismatchedStructFieldName;
LinkMismatchError linkError =
LinkValidateUniforms(uniform, linkedUniform, &mismatchedStructFieldName);
if (linkError != LinkMismatchError::NO_MISMATCH)
{
LogLinkMismatch(infoLog, uniform.name, "uniform", linkError,
mismatchedStructFieldName, entry->second.first,
shaderToLink->getType());
return false;
}
}
else if (extendLinkedUniforms)
{
(*linkedUniforms)[uniform.name] = std::make_pair(shaderToLink->getType(), &uniform);
}
}
return true;
}
} // anonymous namespace
UniformLinker::UniformLinker(const ProgramState &state) : mState(state)
......@@ -114,74 +188,32 @@ bool UniformLinker::link(const Context *context,
bool UniformLinker::validateGraphicsUniforms(const Context *context, InfoLog &infoLog) const
{
// Check that uniforms defined in the vertex and fragment shaders are identical
std::map<std::string, const sh::Uniform *> linkedUniforms;
const std::vector<sh::Uniform> &vertexUniforms =
mState.getAttachedVertexShader()->getUniforms(context);
const std::vector<sh::Uniform> &fragmentUniforms =
mState.getAttachedFragmentShader()->getUniforms(context);
for (const sh::Uniform &vertexUniform : vertexUniforms)
// Check that uniforms defined in the graphics shaders are identical
std::map<std::string, ShaderUniform> linkedUniforms;
for (const sh::Uniform &vertexUniform : mState.getAttachedVertexShader()->getUniforms(context))
{
linkedUniforms[vertexUniform.name] = &vertexUniform;
linkedUniforms[vertexUniform.name] = std::make_pair(GL_VERTEX_SHADER, &vertexUniform);
}
for (const sh::Uniform &fragmentUniform : fragmentUniforms)
std::vector<Shader *> activeShadersToLink;
if (mState.getAttachedGeometryShader())
{
auto entry = linkedUniforms.find(fragmentUniform.name);
if (entry != linkedUniforms.end())
{
const sh::Uniform &vertexUniform = *(entry->second);
std::string mismatchedStructFieldName;
LinkMismatchError linkError =
LinkValidateUniforms(vertexUniform, fragmentUniform, &mismatchedStructFieldName);
if (linkError != LinkMismatchError::NO_MISMATCH)
{
LogLinkMismatch(infoLog, fragmentUniform.name, "uniform", linkError,
mismatchedStructFieldName, GL_VERTEX_SHADER, GL_FRAGMENT_SHADER);
return false;
}
}
activeShadersToLink.push_back(mState.getAttachedGeometryShader());
}
return true;
}
// GLSL ES Spec 3.00.3, section 4.3.5.
LinkMismatchError UniformLinker::LinkValidateUniforms(const sh::Uniform &uniform1,
const sh::Uniform &uniform2,
std::string *mismatchedStructFieldName)
{
#if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED
const bool validatePrecision = true;
#else
const bool validatePrecision = false;
#endif
activeShadersToLink.push_back(mState.getAttachedFragmentShader());
LinkMismatchError linkError = Program::LinkValidateVariablesBase(
uniform1, uniform2, validatePrecision, true, mismatchedStructFieldName);
if (linkError != LinkMismatchError::NO_MISMATCH)
const size_t numActiveShadersToLink = activeShadersToLink.size();
for (size_t shaderIndex = 0; shaderIndex < numActiveShadersToLink; ++shaderIndex)
{
return linkError;
}
// GLSL ES Spec 3.10.4, section 4.4.5.
if (uniform1.binding != -1 && uniform2.binding != -1 && uniform1.binding != uniform2.binding)
{
return LinkMismatchError::BINDING_MISMATCH;
}
// GLSL ES Spec 3.10.4, section 9.2.1.
if (uniform1.location != -1 && uniform2.location != -1 &&
uniform1.location != uniform2.location)
{
return LinkMismatchError::LOCATION_MISMATCH;
}
if (uniform1.offset != uniform2.offset)
{
return LinkMismatchError::OFFSET_MISMATCH;
bool isLastShader = (shaderIndex == numActiveShadersToLink - 1);
if (!ValidateGraphicsUniformsPerShader(context, activeShadersToLink[shaderIndex],
!isLastShader, &linkedUniforms, infoLog))
{
return false;
}
}
return LinkMismatchError::NO_MISMATCH;
return true;
}
bool UniformLinker::indexUniforms(InfoLog &infoLog, const ProgramBindings &uniformLocationBindings)
......@@ -467,6 +499,22 @@ bool UniformLinker::flattenUniformsAndCheckCaps(const Context *context, InfoLog
{
return false;
}
Shader *geometryShader = mState.getAttachedGeometryShader();
// TODO (jiawei.shao@intel.com): check whether we need finer-grained component counting
if (geometryShader &&
!flattenUniformsAndCheckCapsForShader(
context, geometryShader, caps.maxGeometryUniformComponents / 4,
caps.maxGeometryTextureImageUnits, caps.maxGeometryImageUniforms,
caps.maxGeometryAtomicCounters,
"Geometry shader active uniforms exceed MAX_GEOMETRY_UNIFORM_VECTORS_EXT (",
"Geometry shader sampler count exceeds MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT (",
"Geometry shader image count exceeds MAX_GEOMETRY_IMAGE_UNIFORMS_EXT (",
"Geometry shader atomic counter count exceeds MAX_GEOMETRY_ATOMIC_COUNTERS_EXT (",
samplerUniforms, imageUniforms, atomicCounterUniforms, infoLog))
{
return false;
}
}
mUniforms.insert(mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
......
......@@ -81,10 +81,6 @@ class UniformLinker final : angle::NonCopyable
bool validateGraphicsUniforms(const Context *context, InfoLog &infoLog) const;
static LinkMismatchError LinkValidateUniforms(const sh::Uniform &uniform1,
const sh::Uniform &uniform2,
std::string *mismatchedStructFieldName);
bool flattenUniformsAndCheckCapsForShader(const Context *context,
Shader *shader,
GLuint maxUniformComponents,
......
......@@ -14,7 +14,10 @@ namespace gl
{
StaticallyUsed::StaticallyUsed()
: vertexStaticUse(false), fragmentStaticUse(false), computeStaticUse(false)
: vertexStaticUse(false),
fragmentStaticUse(false),
computeStaticUse(false),
geometryStaticUse(false)
{
}
......@@ -41,6 +44,10 @@ void StaticallyUsed::setStaticUse(GLenum shaderType, bool used)
computeStaticUse = used;
break;
case GL_GEOMETRY_SHADER_EXT:
geometryStaticUse = used;
break;
default:
UNREACHABLE();
}
......@@ -51,6 +58,7 @@ void StaticallyUsed::unionReferencesWith(const StaticallyUsed &other)
vertexStaticUse |= other.vertexStaticUse;
fragmentStaticUse |= other.fragmentStaticUse;
computeStaticUse |= other.computeStaticUse;
geometryStaticUse |= other.geometryStaticUse;
}
LinkedUniform::LinkedUniform()
......
......@@ -34,6 +34,7 @@ struct StaticallyUsed
bool vertexStaticUse;
bool fragmentStaticUse;
bool computeStaticUse;
bool geometryStaticUse;
};
// Helper struct representing a single shader uniform
......
......@@ -1117,6 +1117,13 @@
1442 D3D11 : dEQP-GLES31.functional.shaders.builtin_var.compute.local_invocation_id = FAIL
1442 D3D11 : dEQP-GLES31.functional.shaders.builtin_var.compute.global_invocation_id = FAIL
1442 D3D11 : dEQP-GLES31.functional.shaders.builtin_var.compute.local_invocation_index = FAIL
1941 D3D11 : dEQP-GLES31.functional.geometry_shading.basic.* = FAIL
1941 D3D11 : dEQP-GLES31.functional.geometry_shading.conversion.* = FAIL
1941 D3D11 : dEQP-GLES31.functional.geometry_shading.emit.* = FAIL
1941 D3D11 : dEQP-GLES31.functional.geometry_shading.varying.* = FAIL
1941 D3D11 : dEQP-GLES31.functional.geometry_shading.instanced.geometry_* = FAIL
1941 D3D11 : dEQP-GLES31.functional.geometry_shading.instanced.invocation_output_* = FAIL
1941 D3D11 : dEQP-GLES31.functional.geometry_shading.instanced.draw_* = FAIL
1941 D3D11 : dEQP-GLES31.functional.shaders.linkage.es31.geometry.* = FAIL
// OPENGL Failing Tests
......@@ -1633,16 +1640,8 @@
1941 OPENGL D3D11 : dEQP-GLES31.functional.debug.negative_coverage.log.shader_directive.geometry_shader = FAIL
1941 OPENGL D3D11 : dEQP-GLES31.functional.debug.negative_coverage.get_error.shader_directive.geometry_shader = FAIL
1941 OPENGL D3D11 : dEQP-GLES31.functional.geometry_shading.query.* = FAIL
1941 OPENGL D3D11 : dEQP-GLES31.functional.geometry_shading.basic.* = FAIL
1941 OPENGL D3D11 : dEQP-GLES31.functional.geometry_shading.input.* = FAIL
1941 OPENGL D3D11 : dEQP-GLES31.functional.geometry_shading.conversion.* = FAIL
1941 OPENGL D3D11 : dEQP-GLES31.functional.geometry_shading.emit.* = FAIL
1941 OPENGL D3D11 : dEQP-GLES31.functional.geometry_shading.varying.* = FAIL
1941 OPENGL D3D11 : dEQP-GLES31.functional.geometry_shading.instanced.geometry_* = FAIL
1941 OPENGL D3D11 : dEQP-GLES31.functional.geometry_shading.instanced.invocation_output_* = FAIL
1941 OPENGL D3D11 : dEQP-GLES31.functional.geometry_shading.instanced.draw_* = FAIL
1941 OPENGL D3D11 : dEQP-GLES31.functional.geometry_shading.negative.* = FAIL
1941 OPENGL D3D11 : dEQP-GLES31.functional.shaders.linkage.es31.geometry.uniform.* = FAIL
2324 DEBUG RELEASE : dEQP-GLES31.functional.debug.negative_coverage.callbacks.compute.program_not_active = FAIL
2324 DEBUG RELEASE : dEQP-GLES31.functional.debug.negative_coverage.log.compute.program_not_active = FAIL
......
......@@ -316,6 +316,55 @@ TEST_P(GeometryShaderTest, VertexShaderArrayOutput)
EXPECT_GL_NO_ERROR();
}
// Verify that an link error occurs when the definition of a unform in fragment shader is different
// from those in a geometry shader.
TEST_P(GeometryShaderTest, UniformMismatchBetweenGeometryAndFragmentShader)
{
ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_EXT_geometry_shader"));
const std::string &vertexShader =
R"(#version 310 es
uniform highp vec4 uniform_value_vert;
in vec4 vertex_in;
out vec4 vertex_out;
void main()
{
gl_Position = vertex_in;
vertex_out = uniform_value_vert;
})";
const std::string &geometryShader =
R"(#version 310 es
#extension GL_EXT_geometry_shader : require
uniform vec4 uniform_value;
layout (invocations = 3, triangles) in;
layout (points, max_vertices = 3) out;
in vec4 vertex_out[];
out vec4 geometry_color;
void main()
{
gl_Position = gl_in[0].gl_Position;
geometry_color = vertex_out[0] + uniform_value;
EmitVertex();
})";
const std::string &fragmentShader =
R"(#version 310 es
precision highp float;
uniform float uniform_value;
in vec4 geometry_color;
layout (location = 0) out vec4 output_color;
void main()
{
output_color = vec4(geometry_color.rgb, uniform_value);
})";
GLuint program = CompileProgramWithGS(vertexShader, geometryShader, fragmentShader);
EXPECT_EQ(0u, program);
EXPECT_GL_NO_ERROR();
}
ANGLE_INSTANTIATE_TEST(GeometryShaderTestES3, ES3_OPENGL(), ES3_OPENGLES(), ES3_D3D11());
ANGLE_INSTANTIATE_TEST(GeometryShaderTest, ES31_OPENGL(), ES31_OPENGLES(), ES31_D3D11());
}
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