Commit b5cc1198 by Shao Committed by Commit Bot

ES31: Add Geometry Shader layout qualifiers in GLSL compiler

This patch intends to implement Geometry Shader layout qualifiers required in OpenGL ES 3.1 extension GL_OES_geometry_shader in ANGLE GLSL compiler. 1. Add support to the shader type GL_GEOMETRY_SHADER_OES. 2. Implement Geometry Shader layout qualifiers in the GLSL compiler: (1) Add support to OpenGL ES 3.1 extension "GL_OES_geometry_shader". (2) Add validations of the input and output primitive declarations in the Geometry Shader layout declarations. (3) Add 'invocations' and 'max_vertices' support in the Geometry Shader layout declarations 3. Add unit tests to cover all the new features added in this patch. BUG=angleproject:1941 TEST=angle_unittests Change-Id: Ie693e11f8a00dab3552626ed63e9336c7fbd3cb8 Reviewed-on: https://chromium-review.googlesource.com/560647 Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent 4c19a8a8
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
// Version number for shader translation API. // Version number for shader translation API.
// It is incremented every time the API changes. // It is incremented every time the API changes.
#define ANGLE_SH_VERSION 178 #define ANGLE_SH_VERSION 179
enum ShShaderSpec enum ShShaderSpec
{ {
...@@ -291,6 +291,7 @@ struct ShBuiltInResources ...@@ -291,6 +291,7 @@ struct ShBuiltInResources
int ARM_shader_framebuffer_fetch; int ARM_shader_framebuffer_fetch;
int OVR_multiview; int OVR_multiview;
int EXT_YUV_target; int EXT_YUV_target;
int OES_geometry_shader;
// Set to 1 to enable replacing GL_EXT_draw_buffers #extension directives // Set to 1 to enable replacing GL_EXT_draw_buffers #extension directives
// with GL_NV_draw_buffers in ESSL output. This flag can be used to emulate // with GL_NV_draw_buffers in ESSL output. This flag can be used to emulate
...@@ -411,6 +412,12 @@ struct ShBuiltInResources ...@@ -411,6 +412,12 @@ struct ShBuiltInResources
// maximum point size (higher limit from ALIASED_POINT_SIZE_RANGE) // maximum point size (higher limit from ALIASED_POINT_SIZE_RANGE)
float MaxPointSize; float MaxPointSize;
// OES_geometry_shader constants
// TODO(jiawei.shao@intel.com): add complete geometry shader constants.
int MaxGeometryUniformComponents;
int MaxGeometryOutputVertices;
int MaxGeometryShaderInvocations;
}; };
// //
......
...@@ -63,6 +63,7 @@ void GenerateResources(ShBuiltInResources *resources) ...@@ -63,6 +63,7 @@ void GenerateResources(ShBuiltInResources *resources)
resources->OES_standard_derivatives = 0; resources->OES_standard_derivatives = 0;
resources->OES_EGL_image_external = 0; resources->OES_EGL_image_external = 0;
resources->OES_geometry_shader = 1;
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
...@@ -74,6 +75,7 @@ int main(int argc, char *argv[]) ...@@ -74,6 +75,7 @@ int main(int argc, char *argv[])
ShHandle vertexCompiler = 0; ShHandle vertexCompiler = 0;
ShHandle fragmentCompiler = 0; ShHandle fragmentCompiler = 0;
ShHandle computeCompiler = 0; ShHandle computeCompiler = 0;
ShHandle geometryCompiler = 0;
ShShaderSpec spec = SH_GLES2_SPEC; ShShaderSpec spec = SH_GLES2_SPEC;
ShShaderOutput output = SH_ESSL_OUTPUT; ShShaderOutput output = SH_ESSL_OUTPUT;
...@@ -268,7 +270,14 @@ int main(int argc, char *argv[]) ...@@ -268,7 +270,14 @@ int main(int argc, char *argv[])
} }
compiler = computeCompiler; compiler = computeCompiler;
break; break;
case GL_GEOMETRY_SHADER_OES:
if (geometryCompiler == 0)
{
geometryCompiler =
sh::ConstructCompiler(GL_GEOMETRY_SHADER_OES, spec, output, &resources);
}
compiler = geometryCompiler;
break;
default: break; default: break;
} }
if (compiler) if (compiler)
...@@ -307,7 +316,8 @@ int main(int argc, char *argv[]) ...@@ -307,7 +316,8 @@ int main(int argc, char *argv[])
} }
} }
if ((vertexCompiler == 0) && (fragmentCompiler == 0) && (computeCompiler == 0)) if ((vertexCompiler == 0) && (fragmentCompiler == 0) && (computeCompiler == 0) &&
(geometryCompiler == 0))
failCode = EFailUsage; failCode = EFailUsage;
if (failCode == EFailUsage) if (failCode == EFailUsage)
usage(); usage();
...@@ -318,6 +328,8 @@ int main(int argc, char *argv[]) ...@@ -318,6 +328,8 @@ int main(int argc, char *argv[])
sh::Destruct(fragmentCompiler); sh::Destruct(fragmentCompiler);
if (computeCompiler) if (computeCompiler)
sh::Destruct(computeCompiler); sh::Destruct(computeCompiler);
if (geometryCompiler)
sh::Destruct(geometryCompiler);
sh::Finalize(); sh::Finalize();
...@@ -389,6 +401,8 @@ sh::GLenum FindShaderType(const char *fileName) ...@@ -389,6 +401,8 @@ sh::GLenum FindShaderType(const char *fileName)
return GL_VERTEX_SHADER; return GL_VERTEX_SHADER;
if (strncmp(ext, ".comp", 5) == 0) if (strncmp(ext, ".comp", 5) == 0)
return GL_COMPUTE_SHADER; return GL_COMPUTE_SHADER;
if (strncmp(ext, ".geom", 5) == 0)
return GL_GEOMETRY_SHADER_OES;
} }
return GL_FRAGMENT_SHADER; return GL_FRAGMENT_SHADER;
......
...@@ -573,6 +573,10 @@ enum TQualifier ...@@ -573,6 +573,10 @@ enum TQualifier
EvqRestrict, EvqRestrict,
EvqVolatile, EvqVolatile,
// GLSL ES 3.1 extension OES_geometry_shader qualifiers
EvqGeometryIn,
EvqGeometryOut,
// end of list // end of list
EvqLast EvqLast
}; };
...@@ -623,6 +627,18 @@ enum TYuvCscStandardEXT ...@@ -623,6 +627,18 @@ enum TYuvCscStandardEXT
EycsItu709 EycsItu709
}; };
enum TLayoutPrimitiveType
{
EptUndefined,
EptPoints,
EptLines,
EptLinesAdjacency,
EptTriangles,
EptTrianglesAdjacency,
EptLineStrip,
EptTriangleStrip
};
struct TLayoutQualifier struct TLayoutQualifier
{ {
int location; int location;
...@@ -645,6 +661,11 @@ struct TLayoutQualifier ...@@ -645,6 +661,11 @@ struct TLayoutQualifier
// EXT_YUV_target yuv layout qualifier. // EXT_YUV_target yuv layout qualifier.
bool yuv; bool yuv;
// OES_geometry_shader layout qualifiers.
TLayoutPrimitiveType primitiveType;
int invocations;
int maxVertices;
static TLayoutQualifier create() static TLayoutQualifier create()
{ {
TLayoutQualifier layoutQualifier; TLayoutQualifier layoutQualifier;
...@@ -661,6 +682,11 @@ struct TLayoutQualifier ...@@ -661,6 +682,11 @@ struct TLayoutQualifier
layoutQualifier.yuv = false; layoutQualifier.yuv = false;
layoutQualifier.imageInternalFormat = EiifUnspecified; layoutQualifier.imageInternalFormat = EiifUnspecified;
layoutQualifier.primitiveType = EptUndefined;
layoutQualifier.invocations = 0;
layoutQualifier.maxVertices = -1;
return layoutQualifier; return layoutQualifier;
} }
...@@ -668,13 +694,16 @@ struct TLayoutQualifier ...@@ -668,13 +694,16 @@ struct TLayoutQualifier
{ {
return location == -1 && binding == -1 && offset == -1 && numViews == -1 && yuv == false && return location == -1 && binding == -1 && offset == -1 && numViews == -1 && yuv == false &&
matrixPacking == EmpUnspecified && blockStorage == EbsUnspecified && matrixPacking == EmpUnspecified && blockStorage == EbsUnspecified &&
!localSize.isAnyValueSet() && imageInternalFormat == EiifUnspecified; !localSize.isAnyValueSet() && imageInternalFormat == EiifUnspecified &&
primitiveType == EptUndefined && invocations == 0 && maxVertices == -1;
} }
bool isCombinationValid() const bool isCombinationValid() const
{ {
bool workSizeSpecified = localSize.isAnyValueSet(); bool workSizeSpecified = localSize.isAnyValueSet();
bool numViewsSet = (numViews != -1); bool numViewsSet = (numViews != -1);
bool geometryShaderSpecified =
(primitiveType != EptUndefined) || (invocations != 0) || (maxVertices != -1);
bool otherLayoutQualifiersSpecified = bool otherLayoutQualifiersSpecified =
(location != -1 || binding != -1 || matrixPacking != EmpUnspecified || (location != -1 || binding != -1 || matrixPacking != EmpUnspecified ||
blockStorage != EbsUnspecified || imageInternalFormat != EiifUnspecified); blockStorage != EbsUnspecified || imageInternalFormat != EiifUnspecified);
...@@ -682,7 +711,7 @@ struct TLayoutQualifier ...@@ -682,7 +711,7 @@ struct TLayoutQualifier
// we can have either the work group size specified, or number of views, // we can have either the work group size specified, or number of views,
// or yuv layout qualifier, or the other layout qualifiers. // or yuv layout qualifier, or the other layout qualifiers.
return (workSizeSpecified ? 1 : 0) + (numViewsSet ? 1 : 0) + (yuv ? 1 : 0) + return (workSizeSpecified ? 1 : 0) + (numViewsSet ? 1 : 0) + (yuv ? 1 : 0) +
(otherLayoutQualifiersSpecified ? 1 : 0) <= (otherLayoutQualifiersSpecified ? 1 : 0) + (geometryShaderSpecified ? 1 : 0) <=
1; 1;
} }
...@@ -799,6 +828,8 @@ inline const char *getQualifierString(TQualifier q) ...@@ -799,6 +828,8 @@ inline const char *getQualifierString(TQualifier q)
case EvqLocalInvocationIndex: return "LocalInvocationIndex"; case EvqLocalInvocationIndex: return "LocalInvocationIndex";
case EvqReadOnly: return "readonly"; case EvqReadOnly: return "readonly";
case EvqWriteOnly: return "writeonly"; case EvqWriteOnly: return "writeonly";
case EvqGeometryIn: return "in";
case EvqGeometryOut: return "out";
default: UNREACHABLE(); return "unknown qualifier"; default: UNREACHABLE(); return "unknown qualifier";
} }
// clang-format on // clang-format on
...@@ -901,6 +932,30 @@ inline const char *getYuvCscStandardEXTString(TYuvCscStandardEXT ycsq) ...@@ -901,6 +932,30 @@ inline const char *getYuvCscStandardEXTString(TYuvCscStandardEXT ycsq)
} }
} }
inline const char *getGeometryShaderPrimitiveTypeString(TLayoutPrimitiveType primitiveType)
{
switch (primitiveType)
{
case EptPoints:
return "points";
case EptLines:
return "lines";
case EptTriangles:
return "triangles";
case EptLinesAdjacency:
return "lines_adjacency";
case EptTrianglesAdjacency:
return "triangles_adjacency";
case EptLineStrip:
return "line_strip";
case EptTriangleStrip:
return "triangle_strip";
default:
UNREACHABLE();
return "unknown geometry shader primitive type";
}
}
} // namespace sh } // namespace sh
#endif // COMPILER_TRANSLATOR_BASETYPES_H_ #endif // COMPILER_TRANSLATOR_BASETYPES_H_
...@@ -146,11 +146,14 @@ int GetMaxUniformVectorsForShaderType(GLenum shaderType, const ShBuiltInResource ...@@ -146,11 +146,14 @@ int GetMaxUniformVectorsForShaderType(GLenum shaderType, const ShBuiltInResource
return resources.MaxVertexUniformVectors; return resources.MaxVertexUniformVectors;
case GL_FRAGMENT_SHADER: case GL_FRAGMENT_SHADER:
return resources.MaxFragmentUniformVectors; return resources.MaxFragmentUniformVectors;
// TODO (jiawei.shao@intel.com): check if we need finer-grained component counting
case GL_COMPUTE_SHADER: case GL_COMPUTE_SHADER:
// TODO (jiawei.shao@intel.com): check if we need finer-grained component counting
return resources.MaxComputeUniformComponents / 4; return resources.MaxComputeUniformComponents / 4;
case GL_GEOMETRY_SHADER_OES:
return resources.MaxGeometryUniformComponents / 4;
default: default:
UNIMPLEMENTED(); UNREACHABLE();
return -1; return -1;
} }
} }
...@@ -242,7 +245,11 @@ TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output) ...@@ -242,7 +245,11 @@ TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
builtInFunctionEmulator(), builtInFunctionEmulator(),
mDiagnostics(infoSink.info), mDiagnostics(infoSink.info),
mSourcePath(nullptr), mSourcePath(nullptr),
mComputeShaderLocalSizeDeclared(false) mComputeShaderLocalSizeDeclared(false),
mGeometryShaderMaxVertices(-1),
mGeometryShaderInvocations(0),
mGeometryShaderInputPrimitiveType(EptUndefined),
mGeometryShaderOutputPrimitiveType(EptUndefined)
{ {
mComputeShaderLocalSize.fill(1); mComputeShaderLocalSize.fill(1);
} }
...@@ -360,6 +367,15 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[], ...@@ -360,6 +367,15 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
success = false; success = false;
} }
if (success && shaderType == GL_GEOMETRY_SHADER_OES)
{
mGeometryShaderInputPrimitiveType = parseContext.getGeometryShaderInputPrimitiveType();
mGeometryShaderOutputPrimitiveType =
parseContext.getGeometryShaderOutputPrimitiveType();
mGeometryShaderMaxVertices = parseContext.getGeometryShaderMaxVertices();
mGeometryShaderInvocations = parseContext.getGeometryShaderInvocations();
}
// Disallow expressions deemed too complex. // Disallow expressions deemed too complex.
if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY)) if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY))
success = limitExpressionComplexity(root); success = limitExpressionComplexity(root);
...@@ -626,15 +642,13 @@ bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources) ...@@ -626,15 +642,13 @@ bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
symbolTable.setDefaultPrecision(EbtInt, EbpMedium); symbolTable.setDefaultPrecision(EbtInt, EbpMedium);
break; break;
case GL_VERTEX_SHADER: case GL_VERTEX_SHADER:
symbolTable.setDefaultPrecision(EbtInt, EbpHigh);
symbolTable.setDefaultPrecision(EbtFloat, EbpHigh);
break;
case GL_COMPUTE_SHADER: case GL_COMPUTE_SHADER:
case GL_GEOMETRY_SHADER_OES:
symbolTable.setDefaultPrecision(EbtInt, EbpHigh); symbolTable.setDefaultPrecision(EbtInt, EbpHigh);
symbolTable.setDefaultPrecision(EbtFloat, EbpHigh); symbolTable.setDefaultPrecision(EbtFloat, EbpHigh);
break; break;
default: default:
assert(false && "Language not supported"); UNREACHABLE();
} }
// Set defaults for sampler types that have default precision, even those that are // Set defaults for sampler types that have default precision, even those that are
// only available if an extension exists. // only available if an extension exists.
...@@ -694,6 +708,7 @@ void TCompiler::setResourceString() ...@@ -694,6 +708,7 @@ void TCompiler::setResourceString()
<< ":ARM_shader_framebuffer_fetch:" << compileResources.ARM_shader_framebuffer_fetch << ":ARM_shader_framebuffer_fetch:" << compileResources.ARM_shader_framebuffer_fetch
<< ":OVR_multiview:" << compileResources.OVR_multiview << ":OVR_multiview:" << compileResources.OVR_multiview
<< ":EXT_YUV_target:" << compileResources.EXT_YUV_target << ":EXT_YUV_target:" << compileResources.EXT_YUV_target
<< ":OES_geometry_shader:" << compileResources.OES_geometry_shader
<< ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors << ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors
<< ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors << ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors
<< ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset << ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset
...@@ -725,7 +740,10 @@ void TCompiler::setResourceString() ...@@ -725,7 +740,10 @@ void TCompiler::setResourceString()
<< ":MaxVertexAtomicCounterBuffers:" << compileResources.MaxVertexAtomicCounterBuffers << ":MaxVertexAtomicCounterBuffers:" << compileResources.MaxVertexAtomicCounterBuffers
<< ":MaxFragmentAtomicCounterBuffers:" << compileResources.MaxFragmentAtomicCounterBuffers << ":MaxFragmentAtomicCounterBuffers:" << compileResources.MaxFragmentAtomicCounterBuffers
<< ":MaxCombinedAtomicCounterBuffers:" << compileResources.MaxCombinedAtomicCounterBuffers << ":MaxCombinedAtomicCounterBuffers:" << compileResources.MaxCombinedAtomicCounterBuffers
<< ":MaxAtomicCounterBufferSize:" << compileResources.MaxAtomicCounterBufferSize; << ":MaxAtomicCounterBufferSize:" << compileResources.MaxAtomicCounterBufferSize
<< ":MaxGeometryOutputVertices:" << compileResources.MaxGeometryOutputVertices
<< ":MaxGeometryUniformComponents:" << compileResources.MaxGeometryUniformComponents
<< ":MaxGeometryShaderInvocations:" << compileResources.MaxGeometryShaderInvocations;
// clang-format on // clang-format on
builtInResourcesString = strstream.str(); builtInResourcesString = strstream.str();
...@@ -749,6 +767,11 @@ void TCompiler::clearResults() ...@@ -749,6 +767,11 @@ void TCompiler::clearResults()
mNumViews = -1; mNumViews = -1;
mGeometryShaderInputPrimitiveType = EptUndefined;
mGeometryShaderOutputPrimitiveType = EptUndefined;
mGeometryShaderInvocations = 0;
mGeometryShaderMaxVertices = -1;
builtInFunctionEmulator.cleanup(); builtInFunctionEmulator.cleanup();
nameMap.clear(); nameMap.clear();
......
...@@ -125,8 +125,20 @@ class TCompiler : public TShHandleBase ...@@ -125,8 +125,20 @@ class TCompiler : public TShHandleBase
// Get the resources set by InitBuiltInSymbolTable // Get the resources set by InitBuiltInSymbolTable
const ShBuiltInResources &getResources() const; const ShBuiltInResources &getResources() const;
protected: int getGeometryShaderMaxVertices() const { return mGeometryShaderMaxVertices; }
int getGeometryShaderInvocations() const { return mGeometryShaderInvocations; }
TLayoutPrimitiveType getGeometryShaderInputPrimitiveType() const
{
return mGeometryShaderInputPrimitiveType;
}
TLayoutPrimitiveType getGeometryShaderOutputPrimitiveType() const
{
return mGeometryShaderOutputPrimitiveType;
}
sh::GLenum getShaderType() const { return shaderType; } sh::GLenum getShaderType() const { return shaderType; }
protected:
// Initialize symbol-table with built-in symbols. // Initialize symbol-table with built-in symbols.
bool InitBuiltInSymbolTable(const ShBuiltInResources &resources); bool InitBuiltInSymbolTable(const ShBuiltInResources &resources);
// Compute the string representation of the built-in resources // Compute the string representation of the built-in resources
...@@ -241,6 +253,12 @@ class TCompiler : public TShHandleBase ...@@ -241,6 +253,12 @@ class TCompiler : public TShHandleBase
// GL_OVR_multiview num_views. // GL_OVR_multiview num_views.
int mNumViews; int mNumViews;
// geometry shader parameters.
int mGeometryShaderMaxVertices;
int mGeometryShaderInvocations;
TLayoutPrimitiveType mGeometryShaderInputPrimitiveType;
TLayoutPrimitiveType mGeometryShaderOutputPrimitiveType;
// name hashing. // name hashing.
ShHashFunction64 hashFunction; ShHashFunction64 hashFunction;
NameMap nameMap; NameMap nameMap;
......
...@@ -902,6 +902,10 @@ void IdentifyBuiltIns(sh::GLenum type, ...@@ -902,6 +902,10 @@ void IdentifyBuiltIns(sh::GLenum type,
} }
break; break;
case GL_GEOMETRY_SHADER_OES:
// TODO(jiawei.shao@intel.com): add Geometry Shader built-in variables.
break;
default: default:
assert(false && "Language not supported"); assert(false && "Language not supported");
} }
...@@ -942,6 +946,10 @@ void InitExtensionBehavior(const ShBuiltInResources &resources, TExtensionBehavi ...@@ -942,6 +946,10 @@ void InitExtensionBehavior(const ShBuiltInResources &resources, TExtensionBehavi
{ {
extBehavior["GL_EXT_YUV_target"] = EBhUndefined; extBehavior["GL_EXT_YUV_target"] = EBhUndefined;
} }
if (resources.OES_geometry_shader)
{
extBehavior["GL_OES_geometry_shader"] = EBhUndefined;
}
} }
void ResetExtensionBehavior(TExtensionBehavior &extBehavior) void ResetExtensionBehavior(TExtensionBehavior &extBehavior)
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "compiler/translator/OutputGLSLBase.h" #include "compiler/translator/OutputGLSLBase.h"
#include "angle_gl.h"
#include "common/debug.h" #include "common/debug.h"
#include "common/mathutil.h" #include "common/mathutil.h"
#include "compiler/translator/Compiler.h" #include "compiler/translator/Compiler.h"
...@@ -1293,4 +1294,52 @@ void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBloc ...@@ -1293,4 +1294,52 @@ void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBloc
out << "}"; out << "}";
} }
void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out,
sh::TLayoutPrimitiveType inputPrimitive,
int invocations,
sh::TLayoutPrimitiveType outputPrimitive,
int maxVertices)
{
// Omit 'invocations = 1'
if (inputPrimitive != EptUndefined || invocations > 1)
{
out << "layout (";
if (inputPrimitive != EptUndefined)
{
out << getGeometryShaderPrimitiveTypeString(inputPrimitive);
}
if (invocations > 1)
{
if (inputPrimitive != EptUndefined)
{
out << ", ";
}
out << "invocations = " << invocations;
}
out << ") in;\n";
}
if (outputPrimitive != EptUndefined || maxVertices != -1)
{
out << "layout (";
if (outputPrimitive != EptUndefined)
{
out << getGeometryShaderPrimitiveTypeString(outputPrimitive);
}
if (maxVertices != -1)
{
if (outputPrimitive != EptUndefined)
{
out << ", ";
}
out << "max_vertices = " << maxVertices;
}
out << ") out;\n";
}
}
} // namespace sh } // namespace sh
...@@ -109,6 +109,12 @@ class TOutputGLSLBase : public TIntermTraverser ...@@ -109,6 +109,12 @@ class TOutputGLSLBase : public TIntermTraverser
ShCompileOptions mCompileOptions; ShCompileOptions mCompileOptions;
}; };
void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out,
sh::TLayoutPrimitiveType inputPrimitive,
int invocations,
sh::TLayoutPrimitiveType outputPrimitive,
int maxVertices);
} // namespace sh } // namespace sh
#endif // COMPILER_TRANSLATOR_OUTPUTGLSLBASE_H_ #endif // COMPILER_TRANSLATOR_OUTPUTGLSLBASE_H_
...@@ -340,6 +340,14 @@ class TParseContext : angle::NonCopyable ...@@ -340,6 +340,14 @@ class TParseContext : angle::NonCopyable
const TSourceLoc &intValueLine, const TSourceLoc &intValueLine,
const std::string &intValueString, const std::string &intValueString,
int *numViews); int *numViews);
void parseInvocations(int intValue,
const TSourceLoc &intValueLine,
const std::string &intValueString,
int *numInvocations);
void parseMaxVertices(int intValue,
const TSourceLoc &intValueLine,
const std::string &intValueString,
int *numMaxVertices);
TLayoutQualifier parseLayoutQualifier(const TString &qualifierType, TLayoutQualifier parseLayoutQualifier(const TString &qualifierType,
const TSourceLoc &qualifierTypeLine); const TSourceLoc &qualifierTypeLine);
TLayoutQualifier parseLayoutQualifier(const TString &qualifierType, TLayoutQualifier parseLayoutQualifier(const TString &qualifierType,
...@@ -407,6 +415,20 @@ class TParseContext : angle::NonCopyable ...@@ -407,6 +415,20 @@ class TParseContext : angle::NonCopyable
TIntermTyped *falseExpression, TIntermTyped *falseExpression,
const TSourceLoc &line); const TSourceLoc &line);
int getGeometryShaderMaxVertices() const { return mGeometryShaderMaxVertices; }
int getGeometryShaderInvocations() const
{
return (mGeometryShaderInvocations > 0) ? mGeometryShaderInvocations : 1;
}
TLayoutPrimitiveType getGeometryShaderInputPrimitiveType() const
{
return mGeometryShaderInputPrimitiveType;
}
TLayoutPrimitiveType getGeometryShaderOutputPrimitiveType() const
{
return mGeometryShaderOutputPrimitiveType;
}
// TODO(jmadill): make this private // TODO(jmadill): make this private
TSymbolTable &symbolTable; // symbol table that goes with the language currently being parsed TSymbolTable &symbolTable; // symbol table that goes with the language currently being parsed
...@@ -510,6 +532,10 @@ class TParseContext : angle::NonCopyable ...@@ -510,6 +532,10 @@ class TParseContext : angle::NonCopyable
void setAtomicCounterBindingDefaultOffset(const TPublicType &declaration, void setAtomicCounterBindingDefaultOffset(const TPublicType &declaration,
const TSourceLoc &location); const TSourceLoc &location);
bool checkPrimitiveTypeMatchesTypeQualifier(const TTypeQualifier &typeQualifier);
bool parseGeometryShaderInputLayoutQualifier(const TTypeQualifier &typeQualifier);
bool parseGeometryShaderOutputLayoutQualifier(const TTypeQualifier &typeQualifier);
// Set to true when the last/current declarator list was started with an empty declaration. The // Set to true when the last/current declarator list was started with an empty declaration. The
// non-empty declaration error check will need to be performed if the empty declaration is // non-empty declaration error check will need to be performed if the empty declaration is
// followed by a declarator. // followed by a declarator.
...@@ -566,6 +592,14 @@ class TParseContext : angle::NonCopyable ...@@ -566,6 +592,14 @@ class TParseContext : angle::NonCopyable
// Track the state of each atomic counter binding. // Track the state of each atomic counter binding.
std::map<int, AtomicCounterBindingState> mAtomicCounterBindingStates; std::map<int, AtomicCounterBindingState> mAtomicCounterBindingStates;
// Track the geometry shader global parameters declared in layout.
TLayoutPrimitiveType mGeometryShaderInputPrimitiveType;
TLayoutPrimitiveType mGeometryShaderOutputPrimitiveType;
int mGeometryShaderInvocations;
int mGeometryShaderMaxVertices;
int mMaxGeometryShaderInvocations;
int mMaxGeometryShaderMaxVertices;
}; };
int PaParseStrings(size_t count, int PaParseStrings(size_t count,
......
...@@ -606,6 +606,42 @@ TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier, ...@@ -606,6 +606,42 @@ TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier,
joinedQualifier.imageInternalFormat = rightQualifier.imageInternalFormat; joinedQualifier.imageInternalFormat = rightQualifier.imageInternalFormat;
} }
if (rightQualifier.primitiveType != EptUndefined)
{
if (joinedQualifier.primitiveType != EptUndefined &&
joinedQualifier.primitiveType != rightQualifier.primitiveType)
{
diagnostics->error(rightQualifierLocation,
"Cannot have multiple different primitive specifiers",
getGeometryShaderPrimitiveTypeString(rightQualifier.primitiveType));
}
joinedQualifier.primitiveType = rightQualifier.primitiveType;
}
if (rightQualifier.invocations != 0)
{
if (joinedQualifier.invocations != 0 &&
joinedQualifier.invocations != rightQualifier.invocations)
{
diagnostics->error(rightQualifierLocation,
"Cannot have multiple different invocations specifiers",
"invocations");
}
joinedQualifier.invocations = rightQualifier.invocations;
}
if (rightQualifier.maxVertices != -1)
{
if (joinedQualifier.maxVertices != -1 &&
joinedQualifier.maxVertices != rightQualifier.maxVertices)
{
diagnostics->error(rightQualifierLocation,
"Cannot have multiple different max_vertices specifiers",
"max_vertices");
}
joinedQualifier.maxVertices = rightQualifier.maxVertices;
}
return joinedQualifier; return joinedQualifier;
} }
......
...@@ -164,6 +164,7 @@ void InitBuiltInResources(ShBuiltInResources *resources) ...@@ -164,6 +164,7 @@ void InitBuiltInResources(ShBuiltInResources *resources)
resources->ARM_shader_framebuffer_fetch = 0; resources->ARM_shader_framebuffer_fetch = 0;
resources->OVR_multiview = 0; resources->OVR_multiview = 0;
resources->EXT_YUV_target = 0; resources->EXT_YUV_target = 0;
resources->OES_geometry_shader = 0;
resources->NV_draw_buffers = 0; resources->NV_draw_buffers = 0;
...@@ -224,6 +225,11 @@ void InitBuiltInResources(ShBuiltInResources *resources) ...@@ -224,6 +225,11 @@ void InitBuiltInResources(ShBuiltInResources *resources)
resources->MaxAtomicCounterBufferSize = 32; resources->MaxAtomicCounterBufferSize = 32;
resources->MaxUniformBufferBindings = 32; resources->MaxUniformBufferBindings = 32;
// TODO(jiawei.shao@intel.com): add complete geometry shader constants.
resources->MaxGeometryUniformComponents = 1024;
resources->MaxGeometryOutputVertices = 256;
resources->MaxGeometryShaderInvocations = 32;
} }
// //
......
...@@ -95,6 +95,13 @@ void TranslatorESSL::translate(TIntermBlock *root, ShCompileOptions compileOptio ...@@ -95,6 +95,13 @@ void TranslatorESSL::translate(TIntermBlock *root, ShCompileOptions compileOptio
<< ", local_size_z=" << localSize[2] << ") in;\n"; << ", local_size_z=" << localSize[2] << ") in;\n";
} }
if (getShaderType() == GL_GEOMETRY_SHADER_OES)
{
WriteGeometryShaderLayoutQualifiers(
sink, getGeometryShaderInputPrimitiveType(), getGeometryShaderInvocations(),
getGeometryShaderOutputPrimitiveType(), getGeometryShaderMaxVertices());
}
// Write translated shader. // Write translated shader.
TOutputESSL outputESSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), TOutputESSL outputESSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(),
&getSymbolTable(), getShaderType(), shaderVer, precisionEmulation, &getSymbolTable(), getShaderType(), shaderVer, precisionEmulation,
...@@ -153,6 +160,22 @@ void TranslatorESSL::writeExtensionBehavior(ShCompileOptions compileOptions) ...@@ -153,6 +160,22 @@ void TranslatorESSL::writeExtensionBehavior(ShCompileOptions compileOptions)
sink << "#extension GL_NV_viewport_array2 : require\n"; sink << "#extension GL_NV_viewport_array2 : require\n";
} }
} }
else if (iter->first == "GL_OES_geometry_shader")
{
sink << "#ifdef GL_OES_geometry_shader\n"
<< "#extension GL_OES_geometry_shader : " << getBehaviorString(iter->second)
<< "\n"
<< "#elif defined GL_EXT_geometry_shader\n"
<< "#extension GL_EXT_geometry_shader : " << getBehaviorString(iter->second)
<< "\n";
if (iter->second == EBhRequire)
{
sink << "#else\n"
<< "#error \"No geometry shader extensions available.\" // Only generate "
"this if the extension is \"required\"\n";
}
sink << "#endif\n";
}
else else
{ {
sink << "#extension " << iter->first << " : " << getBehaviorString(iter->second) sink << "#extension " << iter->first << " : " << getBehaviorString(iter->second)
......
...@@ -200,6 +200,13 @@ void TranslatorGLSL::translate(TIntermBlock *root, ShCompileOptions compileOptio ...@@ -200,6 +200,13 @@ void TranslatorGLSL::translate(TIntermBlock *root, ShCompileOptions compileOptio
<< ", local_size_z=" << localSize[2] << ") in;\n"; << ", local_size_z=" << localSize[2] << ") in;\n";
} }
if (getShaderType() == GL_GEOMETRY_SHADER_OES)
{
WriteGeometryShaderLayoutQualifiers(
sink, getGeometryShaderInputPrimitiveType(), getGeometryShaderInvocations(),
getGeometryShaderOutputPrimitiveType(), getGeometryShaderMaxVertices());
}
// Write translated shader. // Write translated shader.
TOutputGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), TOutputGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(),
&getSymbolTable(), getShaderType(), getShaderVersion(), getOutputType(), &getSymbolTable(), getShaderType(), getShaderVersion(), getOutputType(),
...@@ -268,6 +275,12 @@ void TranslatorGLSL::writeExtensionBehavior(TIntermNode *root, ShCompileOptions ...@@ -268,6 +275,12 @@ void TranslatorGLSL::writeExtensionBehavior(TIntermNode *root, ShCompileOptions
sink << "#extension GL_ARB_draw_buffers : " << getBehaviorString(iter.second) sink << "#extension GL_ARB_draw_buffers : " << getBehaviorString(iter.second)
<< "\n"; << "\n";
} }
if (iter.first == "GL_OES_geometry_shader")
{
sink << "#extension GL_ARB_geometry_shader4 : " << getBehaviorString(iter.second)
<< "\n";
}
} }
const bool isMultiview = const bool isMultiview =
......
...@@ -64,6 +64,7 @@ ...@@ -64,6 +64,7 @@
'<(angle_path)/src/tests/compiler_tests/FloatLex_test.cpp', '<(angle_path)/src/tests/compiler_tests/FloatLex_test.cpp',
'<(angle_path)/src/tests/compiler_tests/FragDepth_test.cpp', '<(angle_path)/src/tests/compiler_tests/FragDepth_test.cpp',
'<(angle_path)/src/tests/compiler_tests/GLSLCompatibilityOutput_test.cpp', '<(angle_path)/src/tests/compiler_tests/GLSLCompatibilityOutput_test.cpp',
'<(angle_path)/src/tests/compiler_tests/GeometryShader_test.cpp',
'<(angle_path)/src/tests/compiler_tests/InitOutputVariables_test.cpp', '<(angle_path)/src/tests/compiler_tests/InitOutputVariables_test.cpp',
'<(angle_path)/src/tests/compiler_tests/IntermNode_test.cpp', '<(angle_path)/src/tests/compiler_tests/IntermNode_test.cpp',
'<(angle_path)/src/tests/compiler_tests/NV_draw_buffers_test.cpp', '<(angle_path)/src/tests/compiler_tests/NV_draw_buffers_test.cpp',
......
...@@ -93,6 +93,20 @@ class ComputeShaderEnforcePackingValidationTest : public ComputeShaderValidation ...@@ -93,6 +93,20 @@ class ComputeShaderEnforcePackingValidationTest : public ComputeShaderValidation
static constexpr GLint kMaxComputeUniformComponents = 128; static constexpr GLint kMaxComputeUniformComponents = 128;
}; };
class GeometryShaderValidationTest : public ShaderCompileTreeTest
{
public:
GeometryShaderValidationTest() {}
protected:
void initResources(ShBuiltInResources *resources) override
{
resources->OES_geometry_shader = 1;
}
::GLenum getShaderType() const override { return GL_GEOMETRY_SHADER_OES; }
ShShaderSpec getShaderSpec() const override { return SH_GLES3_1_SPEC; }
};
// 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(FragmentShaderValidationTest, FunctionParameterMismatch) TEST_F(FragmentShaderValidationTest, FunctionParameterMismatch)
...@@ -2189,6 +2203,53 @@ TEST_F(FragmentShaderValidationTest, InvalidUseOfLocalSizeX) ...@@ -2189,6 +2203,53 @@ TEST_F(FragmentShaderValidationTest, InvalidUseOfLocalSizeX)
} }
} }
// The local_size layout qualifier is only available in compute shaders.
TEST_F(GeometryShaderValidationTest, InvalidUseOfLocalSizeX)
{
const std::string &shaderString1 =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points, local_size_x = 15) in;\n"
"layout (points, max_vertices = 2) out;\n"
"void main()\n"
"{\n"
"}\n";
const std::string &shaderString2 =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points) in;\n"
"layout (invocations = 2, local_size_x = 15) in;\n"
"layout (points, max_vertices = 2) out;\n"
"void main()\n"
"{\n"
"}\n";
const std::string &shaderString3 =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points) in;\n"
"layout (points, local_size_x = 15, max_vertices = 2) out;\n"
"void main()\n"
"{\n"
"}\n";
const std::string &shaderString4 =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points) in;\n"
"layout (points) out;\n"
"layout (max_vertices = 2, local_size_x = 15) out;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString1) || compile(shaderString2) || compile(shaderString3) ||
compile(shaderString4))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// It is a compile time error to use the gl_WorkGroupSize constant if // It is a compile time error to use the gl_WorkGroupSize constant if
// the local size has not been declared yet. // the local size has not been declared yet.
// GLSL ES 3.10 Revision 4, 7.1.3 Compute Shader Special Variables // GLSL ES 3.10 Revision 4, 7.1.3 Compute Shader Special Variables
...@@ -4086,3 +4147,180 @@ TEST_F(FragmentShaderValidationTest, ArrayAsArraySize) ...@@ -4086,3 +4147,180 @@ TEST_F(FragmentShaderValidationTest, ArrayAsArraySize)
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog; FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
} }
} }
// The input primitive layout qualifier is only available in geometry shaders.
TEST_F(VertexShaderValidationTest, InvalidUseOfInputPrimitives)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(points) in vec4 myInput;\n"
"out vec4 myOutput;\n"
"void main() {\n"
" myOutput = myInput;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// The input primitive layout qualifier is only available in geometry shaders.
TEST_F(FragmentShaderValidationTest, InvalidUseOfInputPrimitives)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(points) in vec4 myInput;\n"
"out vec4 myOutput;\n"
"void main() {\n"
" myOutput = myInput;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// The input primitive layout qualifier is only available in geometry shaders.
TEST_F(ComputeShaderValidationTest, InvalidUseOfInputPrimitives)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(points, local_size_x = 12) in;\n"
"void main()\n"
"{\n"
" uvec3 WorkGroupSize = gl_WorkGroupSize;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// The output primitive layout qualifier is only available in geometry shaders.
TEST_F(VertexShaderValidationTest, InvalidUseOfOutputPrimitives)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"in vec4 myInput;\n"
"layout(points) out vec4 myOutput;\n"
"void main() {\n"
" myOutput = myInput;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// The output primitive layout qualifier is only available in geometry shaders.
TEST_F(FragmentShaderValidationTest, InvalidUseOfOutputPrimitives)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"in vec4 myInput;\n"
"layout(points) out vec4 myOutput;\n"
"void main() {\n"
" myOutput = myInput;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// The 'invocations' layout qualifier is only available in geometry shaders.
TEST_F(VertexShaderValidationTest, InvalidUseOfInvocations)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout (invocations = 3) in vec4 myInput;\n"
"out vec4 myOutput;\n"
"void main() {\n"
" myOutput = myInput;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// The 'invocations' layout qualifier is only available in geometry shaders.
TEST_F(FragmentShaderValidationTest, InvalidUseOfInvocations)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout (invocations = 3) in vec4 myInput;\n"
"out vec4 myOutput;\n"
"void main() {\n"
" myOutput = myInput;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// The 'invocations' layout qualifier is only available in geometry shaders.
TEST_F(ComputeShaderValidationTest, InvalidUseOfInvocations)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(invocations = 3, local_size_x = 12) in;\n"
"void main()\n"
"{\n"
" uvec3 WorkGroupSize = gl_WorkGroupSize;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// The 'max_vertices' layout qualifier is only available in geometry shaders.
TEST_F(VertexShaderValidationTest, InvalidUseOfMaxVertices)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"in vec4 myInput;\n"
"layout(max_vertices = 3) out vec4 myOutput;\n"
"void main() {\n"
" myOutput = myInput;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// The 'max_vertices' layout qualifier is only available in geometry shaders.
TEST_F(FragmentShaderValidationTest, InvalidUseOfMaxVertices)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"in vec4 myInput;\n"
"layout(max_vertices = 3) out vec4 myOutput;\n"
"void main() {\n"
" myOutput = myInput;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << 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