ES31: Implement gl_in in Geometry Shader
This patch intends to implement geometry shader built-in interface
block instance gl_in defined in GL_OES_geometry_shader.
1. Add the definition of gl_in and its interface block gl_PerVertex
into the symbol table.
2. Support gl_Position as a member of gl_in.
3. Set the array size of gl_in when a valid input primitive type is
known.
4. Add check that it should be a compile error to index gl_in or
call length() on gl_in without a valid input primitive declaration.
This patch also adds unit tests to cover all these new features.
BUG=angleproject:1941
TEST=angle_unittests
Change-Id: I8da20c943b29c9ce904834625b396aab6302e1e1
Reviewed-on: https://chromium-review.googlesource.com/605059
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index f1cb9ed..25ee442 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -95,6 +95,27 @@
return true;
}
+// Map input primitive types to input array sizes in a geometry shader.
+GLuint GetGeometryShaderInputArraySize(TLayoutPrimitiveType primitiveType)
+{
+ switch (primitiveType)
+ {
+ case EptPoints:
+ return 1u;
+ case EptLines:
+ return 2u;
+ case EptTriangles:
+ return 3u;
+ case EptLinesAdjacency:
+ return 4u;
+ case EptTrianglesAdjacency:
+ return 6u;
+ default:
+ UNREACHABLE();
+ return 0u;
+ }
+}
+
} // namespace
// This tracks each binding point's current default offset for inheritance of subsequent
@@ -184,7 +205,8 @@
mGeometryShaderInvocations(0),
mGeometryShaderMaxVertices(-1),
mMaxGeometryShaderInvocations(resources.MaxGeometryShaderInvocations),
- mMaxGeometryShaderMaxVertices(resources.MaxGeometryOutputVertices)
+ mMaxGeometryShaderMaxVertices(resources.MaxGeometryOutputVertices),
+ mGeometryShaderInputArraySize(0)
{
mComputeShaderLocalSize.fill(-1);
}
@@ -496,6 +518,9 @@
case EvqComputeIn:
message = "can't modify work group size variable";
break;
+ case EvqPerVertexIn:
+ message = "can't modify any member in gl_in";
+ break;
default:
//
// Type that can't be written to?
@@ -1748,6 +1773,13 @@
type.setQualifier(EvqConst);
node = new TIntermConstantUnion(constArray, type);
}
+ // TODO(jiawei.shao@intel.com): set array sizes for user-defined geometry shader inputs.
+ else if (variable->getType().getQualifier() == EvqPerVertexIn)
+ {
+ TType type(variable->getType());
+ type.setArraySize(mGeometryShaderInputArraySize);
+ node = new TIntermSymbol(variable->getUniqueId(), variable->getName(), type);
+ }
else
{
node = new TIntermSymbol(variable->getUniqueId(), variable->getName(), variable->getType());
@@ -2683,6 +2715,15 @@
}
}
+void TParseContext::setGeometryShaderInputArraySizes()
+{
+ // TODO(jiawei.shao@intel.com): check former input array sizes match the input primitive
+ // declaration.
+ ASSERT(mGeometryShaderInputArraySize == 0);
+ mGeometryShaderInputArraySize =
+ GetGeometryShaderInputArraySize(mGeometryShaderInputPrimitiveType);
+}
+
bool TParseContext::parseGeometryShaderInputLayoutQualifier(const TTypeQualifier &typeQualifier)
{
ASSERT(typeQualifier.qualifier == EvqGeometryIn);
@@ -2708,6 +2749,7 @@
if (mGeometryShaderInputPrimitiveType == EptUndefined)
{
mGeometryShaderInputPrimitiveType = layoutQualifier.primitiveType;
+ setGeometryShaderInputArraySizes();
}
else if (mGeometryShaderInputPrimitiveType != layoutQualifier.primitiveType)
{
@@ -3337,6 +3379,7 @@
//
// Interface/uniform blocks
+// TODO(jiawei.shao@intel.com): implement GL_OES_shader_io_blocks.
//
TIntermDeclaration *TParseContext::addInterfaceBlock(
const TTypeQualifierBuilder &typeQualifierBuilder,
@@ -3641,6 +3684,16 @@
return CreateZeroNode(TType(EbtFloat, EbpHigh, EvqConst));
}
+ if (baseExpression->getQualifier() == EvqPerVertexIn)
+ {
+ ASSERT(mShaderType == GL_GEOMETRY_SHADER_OES);
+ if (mGeometryShaderInputPrimitiveType == EptUndefined)
+ {
+ error(location, "missing input primitive declaration before indexing gl_in.", "[");
+ return CreateZeroNode(TType(EbtFloat, EbpHigh, EvqConst));
+ }
+ }
+
TIntermConstantUnion *indexConstantUnion = indexExpression->getAsConstantUnion();
// TODO(oetuaho@nvidia.com): Get rid of indexConstantUnion == nullptr below once ANGLE is able
@@ -3651,9 +3704,21 @@
{
if (baseExpression->isInterfaceBlock())
{
- error(location,
- "array indexes for interface blocks arrays must be constant integral expressions",
- "[");
+ // TODO(jiawei.shao@intel.com): implement GL_OES_shader_io_blocks.
+ switch (baseExpression->getQualifier())
+ {
+ case EvqPerVertexIn:
+ break;
+ case EvqUniform:
+ case EvqBuffer:
+ error(location,
+ "array indexes for uniform block arrays and shader storage block arrays "
+ "must be constant integral expressions",
+ "[");
+ break;
+ default:
+ UNREACHABLE();
+ }
}
else if (baseExpression->getQualifier() == EvqFragmentOut)
{
@@ -5326,6 +5391,11 @@
{
error(loc, "length can only be called on arrays", "length");
}
+ else if (typedThis->getQualifier() == EvqPerVertexIn &&
+ mGeometryShaderInputPrimitiveType == EptUndefined)
+ {
+ error(loc, "missing input primitive declaration before calling length on gl_in", "length");
+ }
else
{
arraySize = typedThis->getArraySize();