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: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/MemoryProgramCache.cpp b/src/libANGLE/MemoryProgramCache.cpp
index 89721fd..aa9cc64 100644
--- a/src/libANGLE/MemoryProgramCache.cpp
+++ b/src/libANGLE/MemoryProgramCache.cpp
@@ -67,6 +67,7 @@
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 @@
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++)
diff --git a/src/libANGLE/Program.cpp b/src/libANGLE/Program.cpp
index ec32a15..2b29002 100644
--- a/src/libANGLE/Program.cpp
+++ b/src/libANGLE/Program.cpp
@@ -2466,7 +2466,7 @@
}
}
// 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 @@
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 @@
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;
}
diff --git a/src/libANGLE/ProgramLinkedResources.cpp b/src/libANGLE/ProgramLinkedResources.cpp
index 158f5ae..a372ff4 100644
--- a/src/libANGLE/ProgramLinkedResources.cpp
+++ b/src/libANGLE/ProgramLinkedResources.cpp
@@ -64,6 +64,80 @@
}
}
+// 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,76 +188,34 @@
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())
+ activeShadersToLink.push_back(mState.getAttachedGeometryShader());
+ }
+ activeShadersToLink.push_back(mState.getAttachedFragmentShader());
+
+ const size_t numActiveShadersToLink = activeShadersToLink.size();
+ for (size_t shaderIndex = 0; shaderIndex < numActiveShadersToLink; ++shaderIndex)
+ {
+ bool isLastShader = (shaderIndex == numActiveShadersToLink - 1);
+ if (!ValidateGraphicsUniformsPerShader(context, activeShadersToLink[shaderIndex],
+ !isLastShader, &linkedUniforms, infoLog))
{
- 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;
- }
+ return false;
}
}
+
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
-
- 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;
-}
-
bool UniformLinker::indexUniforms(InfoLog &infoLog, const ProgramBindings &uniformLocationBindings)
{
// All the locations where another uniform can't be located.
@@ -467,6 +499,22 @@
{
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());
diff --git a/src/libANGLE/ProgramLinkedResources.h b/src/libANGLE/ProgramLinkedResources.h
index ba06d48..83c6fad 100644
--- a/src/libANGLE/ProgramLinkedResources.h
+++ b/src/libANGLE/ProgramLinkedResources.h
@@ -81,10 +81,6 @@
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,
diff --git a/src/libANGLE/Uniform.cpp b/src/libANGLE/Uniform.cpp
index dee8eee..7175118 100644
--- a/src/libANGLE/Uniform.cpp
+++ b/src/libANGLE/Uniform.cpp
@@ -14,7 +14,10 @@
{
StaticallyUsed::StaticallyUsed()
- : vertexStaticUse(false), fragmentStaticUse(false), computeStaticUse(false)
+ : vertexStaticUse(false),
+ fragmentStaticUse(false),
+ computeStaticUse(false),
+ geometryStaticUse(false)
{
}
@@ -41,6 +44,10 @@
computeStaticUse = used;
break;
+ case GL_GEOMETRY_SHADER_EXT:
+ geometryStaticUse = used;
+ break;
+
default:
UNREACHABLE();
}
@@ -51,6 +58,7 @@
vertexStaticUse |= other.vertexStaticUse;
fragmentStaticUse |= other.fragmentStaticUse;
computeStaticUse |= other.computeStaticUse;
+ geometryStaticUse |= other.geometryStaticUse;
}
LinkedUniform::LinkedUniform()
diff --git a/src/libANGLE/Uniform.h b/src/libANGLE/Uniform.h
index 14c3938..03ba67b 100644
--- a/src/libANGLE/Uniform.h
+++ b/src/libANGLE/Uniform.h
@@ -34,6 +34,7 @@
bool vertexStaticUse;
bool fragmentStaticUse;
bool computeStaticUse;
+ bool geometryStaticUse;
};
// Helper struct representing a single shader uniform
diff --git a/src/tests/deqp_support/deqp_gles31_test_expectations.txt b/src/tests/deqp_support/deqp_gles31_test_expectations.txt
index 692cf17..51ff53b 100644
--- a/src/tests/deqp_support/deqp_gles31_test_expectations.txt
+++ b/src/tests/deqp_support/deqp_gles31_test_expectations.txt
@@ -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
diff --git a/src/tests/gl_tests/GeometryShaderTest.cpp b/src/tests/gl_tests/GeometryShaderTest.cpp
index 93afb94..eefd653 100644
--- a/src/tests/gl_tests/GeometryShaderTest.cpp
+++ b/src/tests/gl_tests/GeometryShaderTest.cpp
@@ -316,6 +316,55 @@
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());
}