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_
...@@ -178,7 +178,13 @@ TParseContext::TParseContext(TSymbolTable &symt, ...@@ -178,7 +178,13 @@ TParseContext::TParseContext(TSymbolTable &symt,
mMaxUniformBufferBindings(resources.MaxUniformBufferBindings), mMaxUniformBufferBindings(resources.MaxUniformBufferBindings),
mMaxAtomicCounterBindings(resources.MaxAtomicCounterBindings), mMaxAtomicCounterBindings(resources.MaxAtomicCounterBindings),
mMaxShaderStorageBufferBindings(resources.MaxShaderStorageBufferBindings), mMaxShaderStorageBufferBindings(resources.MaxShaderStorageBufferBindings),
mDeclaringFunction(false) mDeclaringFunction(false),
mGeometryShaderInputPrimitiveType(EptUndefined),
mGeometryShaderOutputPrimitiveType(EptUndefined),
mGeometryShaderInvocations(0),
mGeometryShaderMaxVertices(-1),
mMaxGeometryShaderInvocations(resources.MaxGeometryShaderInvocations),
mMaxGeometryShaderMaxVertices(resources.MaxGeometryOutputVertices)
{ {
mComputeShaderLocalSize.fill(-1); mComputeShaderLocalSize.fill(-1);
} }
...@@ -2654,6 +2660,133 @@ void TParseContext::parseDefaultPrecisionQualifier(const TPrecision precision, ...@@ -2654,6 +2660,133 @@ void TParseContext::parseDefaultPrecisionQualifier(const TPrecision precision,
symbolTable.setDefaultPrecision(type.getBasicType(), precision); symbolTable.setDefaultPrecision(type.getBasicType(), precision);
} }
bool TParseContext::checkPrimitiveTypeMatchesTypeQualifier(const TTypeQualifier &typeQualifier)
{
switch (typeQualifier.layoutQualifier.primitiveType)
{
case EptLines:
case EptLinesAdjacency:
case EptTriangles:
case EptTrianglesAdjacency:
return typeQualifier.qualifier == EvqGeometryIn;
case EptLineStrip:
case EptTriangleStrip:
return typeQualifier.qualifier == EvqGeometryOut;
case EptPoints:
return true;
default:
UNREACHABLE();
return false;
}
}
bool TParseContext::parseGeometryShaderInputLayoutQualifier(const TTypeQualifier &typeQualifier)
{
ASSERT(typeQualifier.qualifier == EvqGeometryIn);
const TLayoutQualifier &layoutQualifier = typeQualifier.layoutQualifier;
if (layoutQualifier.maxVertices != -1)
{
error(typeQualifier.line,
"max_vertices can only be declared in 'out' layout in a geometry shader", "layout");
return false;
}
// Set mGeometryInputPrimitiveType if exists
if (layoutQualifier.primitiveType != EptUndefined)
{
if (!checkPrimitiveTypeMatchesTypeQualifier(typeQualifier))
{
error(typeQualifier.line, "invalid primitive type for 'in' layout", "layout");
return false;
}
if (mGeometryShaderInputPrimitiveType == EptUndefined)
{
mGeometryShaderInputPrimitiveType = layoutQualifier.primitiveType;
}
else if (mGeometryShaderInputPrimitiveType != layoutQualifier.primitiveType)
{
error(typeQualifier.line, "primitive doesn't match earlier input primitive declaration",
"layout");
return false;
}
}
// Set mGeometryInvocations if exists
if (layoutQualifier.invocations > 0)
{
if (mGeometryShaderInvocations == 0)
{
mGeometryShaderInvocations = layoutQualifier.invocations;
}
else if (mGeometryShaderInvocations != layoutQualifier.invocations)
{
error(typeQualifier.line, "invocations contradicts to the earlier declaration",
"layout");
return false;
}
}
return true;
}
bool TParseContext::parseGeometryShaderOutputLayoutQualifier(const TTypeQualifier &typeQualifier)
{
ASSERT(typeQualifier.qualifier == EvqGeometryOut);
const TLayoutQualifier &layoutQualifier = typeQualifier.layoutQualifier;
if (layoutQualifier.invocations > 0)
{
error(typeQualifier.line,
"invocations can only be declared in 'in' layout in a geometry shader", "layout");
return false;
}
// Set mGeometryOutputPrimitiveType if exists
if (layoutQualifier.primitiveType != EptUndefined)
{
if (!checkPrimitiveTypeMatchesTypeQualifier(typeQualifier))
{
error(typeQualifier.line, "invalid primitive type for 'out' layout", "layout");
return false;
}
if (mGeometryShaderOutputPrimitiveType == EptUndefined)
{
mGeometryShaderOutputPrimitiveType = layoutQualifier.primitiveType;
}
else if (mGeometryShaderOutputPrimitiveType != layoutQualifier.primitiveType)
{
error(typeQualifier.line,
"primitive doesn't match earlier output primitive declaration", "layout");
return false;
}
}
// Set mGeometryMaxVertices if exists
if (layoutQualifier.maxVertices > -1)
{
if (mGeometryShaderMaxVertices == -1)
{
mGeometryShaderMaxVertices = layoutQualifier.maxVertices;
}
else if (mGeometryShaderMaxVertices != layoutQualifier.maxVertices)
{
error(typeQualifier.line, "max_vertices contradicts to the earlier declaration",
"layout");
return false;
}
}
return true;
}
void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &typeQualifierBuilder) void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &typeQualifierBuilder)
{ {
TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics); TTypeQualifier typeQualifier = typeQualifierBuilder.getVariableTypeQualifier(mDiagnostics);
...@@ -2735,6 +2868,33 @@ void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &type ...@@ -2735,6 +2868,33 @@ void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &type
mComputeShaderLocalSizeDeclared = true; mComputeShaderLocalSizeDeclared = true;
} }
else if (typeQualifier.qualifier == EvqGeometryIn)
{
if (mShaderVersion < 310)
{
error(typeQualifier.line, "in type qualifier supported in GLSL ES 3.10 only", "layout");
return;
}
if (!parseGeometryShaderInputLayoutQualifier(typeQualifier))
{
return;
}
}
else if (typeQualifier.qualifier == EvqGeometryOut)
{
if (mShaderVersion < 310)
{
error(typeQualifier.line, "out type qualifier supported in GLSL ES 3.10 only",
"layout");
return;
}
if (!parseGeometryShaderOutputLayoutQualifier(typeQualifier))
{
return;
}
}
else if (isMultiviewExtensionEnabled() && typeQualifier.qualifier == EvqVertexIn) else if (isMultiviewExtensionEnabled() && typeQualifier.qualifier == EvqVertexIn)
{ {
// This error is only specified in WebGL, but tightens unspecified behavior in the native // This error is only specified in WebGL, but tightens unspecified behavior in the native
...@@ -3833,6 +3993,48 @@ TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierTyp ...@@ -3833,6 +3993,48 @@ TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierTyp
checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310); checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
qualifier.imageInternalFormat = EiifR32UI; qualifier.imageInternalFormat = EiifR32UI;
} }
else if (qualifierType == "points" && isExtensionEnabled("GL_OES_geometry_shader") &&
mShaderType == GL_GEOMETRY_SHADER_OES)
{
checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
qualifier.primitiveType = EptPoints;
}
else if (qualifierType == "lines" && isExtensionEnabled("GL_OES_geometry_shader") &&
mShaderType == GL_GEOMETRY_SHADER_OES)
{
checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
qualifier.primitiveType = EptLines;
}
else if (qualifierType == "lines_adjacency" && isExtensionEnabled("GL_OES_geometry_shader") &&
mShaderType == GL_GEOMETRY_SHADER_OES)
{
checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
qualifier.primitiveType = EptLinesAdjacency;
}
else if (qualifierType == "triangles" && isExtensionEnabled("GL_OES_geometry_shader") &&
mShaderType == GL_GEOMETRY_SHADER_OES)
{
checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
qualifier.primitiveType = EptTriangles;
}
else if (qualifierType == "triangles_adjacency" &&
isExtensionEnabled("GL_OES_geometry_shader") && mShaderType == GL_GEOMETRY_SHADER_OES)
{
checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
qualifier.primitiveType = EptTrianglesAdjacency;
}
else if (qualifierType == "line_strip" && isExtensionEnabled("GL_OES_geometry_shader") &&
mShaderType == GL_GEOMETRY_SHADER_OES)
{
checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
qualifier.primitiveType = EptLineStrip;
}
else if (qualifierType == "triangle_strip" && isExtensionEnabled("GL_OES_geometry_shader") &&
mShaderType == GL_GEOMETRY_SHADER_OES)
{
checkLayoutQualifierSupported(qualifierTypeLine, qualifierType, 310);
qualifier.primitiveType = EptTriangleStrip;
}
else else
{ {
...@@ -3875,6 +4077,46 @@ void TParseContext::parseNumViews(int intValue, ...@@ -3875,6 +4077,46 @@ void TParseContext::parseNumViews(int intValue,
*numViews = intValue; *numViews = intValue;
} }
void TParseContext::parseInvocations(int intValue,
const TSourceLoc &intValueLine,
const std::string &intValueString,
int *numInvocations)
{
// Although SPEC isn't clear whether invocations can be less than 1, we add this limit because
// it doesn't make sense to accept invocations <= 0.
if (intValue < 1 || intValue > mMaxGeometryShaderInvocations)
{
error(intValueLine,
"out of range: invocations must be in the range of [1, "
"MAX_GEOMETRY_SHADER_INVOCATIONS_OES]",
intValueString.c_str());
}
else
{
*numInvocations = intValue;
}
}
void TParseContext::parseMaxVertices(int intValue,
const TSourceLoc &intValueLine,
const std::string &intValueString,
int *maxVertices)
{
// Although SPEC isn't clear whether max_vertices can be less than 0, we add this limit because
// it doesn't make sense to accept max_vertices < 0.
if (intValue < 0 || intValue > mMaxGeometryShaderMaxVertices)
{
error(
intValueLine,
"out of range: max_vertices must be in the range of [0, gl_MaxGeometryOutputVertices]",
intValueString.c_str());
}
else
{
*maxVertices = intValue;
}
}
TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType, TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType,
const TSourceLoc &qualifierTypeLine, const TSourceLoc &qualifierTypeLine,
int intValue, int intValue,
...@@ -3944,6 +4186,17 @@ TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierTyp ...@@ -3944,6 +4186,17 @@ TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierTyp
{ {
parseNumViews(intValue, intValueLine, intValueString, &qualifier.numViews); parseNumViews(intValue, intValueLine, intValueString, &qualifier.numViews);
} }
else if (qualifierType == "invocations" && isExtensionEnabled("GL_OES_geometry_shader") &&
mShaderType == GL_GEOMETRY_SHADER_OES)
{
parseInvocations(intValue, intValueLine, intValueString, &qualifier.invocations);
}
else if (qualifierType == "max_vertices" && isExtensionEnabled("GL_OES_geometry_shader") &&
mShaderType == GL_GEOMETRY_SHADER_OES)
{
parseMaxVertices(intValue, intValueLine, intValueString, &qualifier.maxVertices);
}
else else
{ {
error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str()); error(qualifierTypeLine, "invalid layout qualifier", qualifierType.c_str());
...@@ -3981,23 +4234,39 @@ TStorageQualifierWrapper *TParseContext::parseInQualifier(const TSourceLoc &loc) ...@@ -3981,23 +4234,39 @@ TStorageQualifierWrapper *TParseContext::parseInQualifier(const TSourceLoc &loc)
{ {
return new TStorageQualifierWrapper(EvqIn, loc); return new TStorageQualifierWrapper(EvqIn, loc);
} }
if (getShaderType() == GL_FRAGMENT_SHADER)
switch (getShaderType())
{ {
if (mShaderVersion < 300) case GL_VERTEX_SHADER:
{ {
error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "in"); if (mShaderVersion < 300 && !isMultiviewExtensionEnabled())
{
error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "in");
}
return new TStorageQualifierWrapper(EvqVertexIn, loc);
} }
return new TStorageQualifierWrapper(EvqFragmentIn, loc); case GL_FRAGMENT_SHADER:
} {
if (getShaderType() == GL_VERTEX_SHADER) if (mShaderVersion < 300)
{ {
if (mShaderVersion < 300 && !isMultiviewExtensionEnabled()) error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "in");
}
return new TStorageQualifierWrapper(EvqFragmentIn, loc);
}
case GL_COMPUTE_SHADER:
{ {
error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "in"); return new TStorageQualifierWrapper(EvqComputeIn, loc);
}
case GL_GEOMETRY_SHADER_OES:
{
return new TStorageQualifierWrapper(EvqGeometryIn, loc);
}
default:
{
UNREACHABLE();
return new TStorageQualifierWrapper(EvqLast, loc);
} }
return new TStorageQualifierWrapper(EvqVertexIn, loc);
} }
return new TStorageQualifierWrapper(EvqComputeIn, loc);
} }
TStorageQualifierWrapper *TParseContext::parseOutQualifier(const TSourceLoc &loc) TStorageQualifierWrapper *TParseContext::parseOutQualifier(const TSourceLoc &loc)
...@@ -4006,19 +4275,39 @@ TStorageQualifierWrapper *TParseContext::parseOutQualifier(const TSourceLoc &loc ...@@ -4006,19 +4275,39 @@ TStorageQualifierWrapper *TParseContext::parseOutQualifier(const TSourceLoc &loc
{ {
return new TStorageQualifierWrapper(EvqOut, loc); return new TStorageQualifierWrapper(EvqOut, loc);
} }
if (mShaderVersion < 300) switch (getShaderType())
{
error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "out");
}
if (getShaderType() != GL_VERTEX_SHADER && getShaderType() != GL_FRAGMENT_SHADER)
{
error(loc, "storage qualifier supported in vertex and fragment shaders only", "out");
}
if (getShaderType() == GL_VERTEX_SHADER)
{ {
return new TStorageQualifierWrapper(EvqVertexOut, loc); case GL_VERTEX_SHADER:
{
if (mShaderVersion < 300)
{
error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "out");
}
return new TStorageQualifierWrapper(EvqVertexOut, loc);
}
case GL_FRAGMENT_SHADER:
{
if (mShaderVersion < 300)
{
error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "out");
}
return new TStorageQualifierWrapper(EvqFragmentOut, loc);
}
case GL_COMPUTE_SHADER:
{
error(loc, "storage qualifier isn't supported in compute shaders", "out");
return new TStorageQualifierWrapper(EvqLast, loc);
}
case GL_GEOMETRY_SHADER_OES:
{
return new TStorageQualifierWrapper(EvqGeometryOut, loc);
}
default:
{
UNREACHABLE();
return new TStorageQualifierWrapper(EvqLast, loc);
}
} }
return new TStorageQualifierWrapper(EvqFragmentOut, loc);
} }
TStorageQualifierWrapper *TParseContext::parseInOutQualifier(const TSourceLoc &loc) TStorageQualifierWrapper *TParseContext::parseInOutQualifier(const TSourceLoc &loc)
......
...@@ -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',
......
//
// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// GeometryShader_test.cpp:
// tests for compiling a Geometry Shader
//
#include "GLSLANG/ShaderLang.h"
#include "angle_gl.h"
#include "compiler/translator/BaseTypes.h"
#include "compiler/translator/TranslatorESSL.h"
#include "gtest/gtest.h"
#include "tests/test_utils/compiler_test.h"
using namespace sh;
class GeometryShaderTest : public testing::Test
{
public:
GeometryShaderTest() {}
protected:
void SetUp() override
{
ShBuiltInResources resources;
InitBuiltInResources(&resources);
resources.OES_geometry_shader = 1;
mTranslator = new TranslatorESSL(GL_GEOMETRY_SHADER_OES, SH_GLES3_1_SPEC);
ASSERT_TRUE(mTranslator->Init(resources));
}
void TearDown() override { SafeDelete(mTranslator); }
// Return true when compilation succeeds
bool compile(const std::string &shaderString)
{
const char *shaderStrings[] = {shaderString.c_str()};
bool status = mTranslator->compile(shaderStrings, 1, SH_OBJECT_CODE | SH_VARIABLES);
TInfoSink &infoSink = mTranslator->getInfoSink();
mInfoLog = infoSink.info.c_str();
return status;
}
bool compileGeometryShader(const std::string &statement1, const std::string &statement2)
{
std::ostringstream sstream;
sstream << kHeader << statement1 << statement2 << kEmptyBody;
return compile(sstream.str());
}
bool compileGeometryShader(const std::string &statement1,
const std::string &statement2,
const std::string &statement3,
const std::string &statement4)
{
std::ostringstream sstream;
sstream << kHeader << statement1 << statement2 << statement3 << statement4 << kEmptyBody;
return compile(sstream.str());
}
static std::string GetGeometryShaderLayout(const std::string &layoutType,
const std::string &primitive,
int invocations,
int maxVertices)
{
std::ostringstream sstream;
sstream << "layout (";
if (!primitive.empty())
{
sstream << primitive;
}
if (invocations > 0)
{
sstream << ", invocations = " << invocations;
}
if (maxVertices >= 0)
{
sstream << ", max_vertices = " << maxVertices;
}
sstream << ") " << layoutType << ";" << std::endl;
return sstream.str();
}
const std::string kHeader =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n";
const std::string kEmptyBody =
"void main()\n"
"{\n"
"}\n";
const std::string kInputLayout = "layout (points) in;\n";
const std::string kOutputLayout = "layout (points, max_vertices = 1) out;\n";
std::string mInfoLog;
TranslatorESSL *mTranslator = nullptr;
};
// Geometry Shaders are not supported in GLSL ES shaders version lower than 310.
TEST_F(GeometryShaderTest, Version300)
{
const std::string &shaderString =
"#version 300 es\n"
"layout(points) in;\n"
"layout(points, max_vertices = 1) out;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Geometry Shaders are not supported in GLSL ES shaders version 310 without extension
// OES_geometry_shader enabled.
TEST_F(GeometryShaderTest, Version310WithoutExtension)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(points) in;\n"
"layout(points, max_vertices = 1) out;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Geometry Shaders are supported in GLSL ES shaders version 310 with OES_geometry_shader enabled.
TEST_F(GeometryShaderTest, Version310WithOESExtension)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout(points) in;\n"
"layout(points, max_vertices = 1) out;\n"
"void main()\n"
"{\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Missing the declaration of input primitive in a geometry shader should be a link error instead of
// a compile error.
TEST_F(GeometryShaderTest, NoInputPrimitives)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout(points, max_vertices = 1) out;\n"
"void main()\n"
"{\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Geometry Shaders can only support 5 kinds of input primitives, which cannot be used as output
// primitives except 'points'.
// Skip testing "points" as it can be used as both input and output primitives.
TEST_F(GeometryShaderTest, ValidInputPrimitives)
{
const std::array<std::string, 4> kInputPrimitives = {
{"lines", "lines_adjacency", "triangles", "triangles_adjacency"}};
for (const std::string &inputPrimitive : kInputPrimitives)
{
if (!compileGeometryShader(GetGeometryShaderLayout("in", inputPrimitive, -1, -1),
kOutputLayout))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
if (compileGeometryShader(kInputLayout,
GetGeometryShaderLayout("out", inputPrimitive, -1, 6)))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
}
// Geometry Shaders allow duplicated declaration of input primitive, but all of them must be same.
TEST_F(GeometryShaderTest, RedeclareInputPrimitives)
{
const std::array<std::string, 5> kInputPrimitives = {
{"points", "lines", "lines_adjacency", "triangles", "triangles_adjacency"}};
for (GLuint i = 0; i < kInputPrimitives.size(); ++i)
{
const std::string &inputLayoutStr1 =
GetGeometryShaderLayout("in", kInputPrimitives[i], -1, -1);
if (!compileGeometryShader(inputLayoutStr1, inputLayoutStr1, kOutputLayout, ""))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
for (GLuint j = i + 1; j < kInputPrimitives.size(); ++j)
{
const std::string &inputLayoutStr2 =
GetGeometryShaderLayout("in", kInputPrimitives[j], -1, -1);
if (compileGeometryShader(inputLayoutStr1, inputLayoutStr2, kOutputLayout, ""))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
}
}
// Geometry Shaders don't allow declaring different input primitives in one layout.
TEST_F(GeometryShaderTest, DeclareDifferentInputPrimitivesInOneLayout)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points, triangles) in;\n"
"layout (points, max_vertices = 1) out;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Geometry Shaders don't allow 'invocations' < 1.
TEST_F(GeometryShaderTest, InvocationsLessThanOne)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points, invocations = 0) in;\n"
"layout (points, max_vertices = 1) out;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Geometry Shaders allow declaring 'invocations' == 1 together with input primitive declaration in
// one layout.
TEST_F(GeometryShaderTest, InvocationsEqualsOne)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points, invocations = 1) in;\n"
"layout (points, max_vertices = 1) out;\n"
"void main()\n"
"{\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Geometry Shaders allow declaring 'invocations' == 1 in an individual layout.
TEST_F(GeometryShaderTest, InvocationsEqualsOneInSeparatedLayout)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points) in;\n"
"layout (invocations = 1) in;\n"
"layout (points, max_vertices = 1) out;\n"
"void main()\n"
"{\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Geometry Shaders don't allow 'invocations' larger than the implementation-dependent maximum value
// (32 in this test).
TEST_F(GeometryShaderTest, TooLargeInvocations)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points, invocations = 9989899) in;\n"
"layout (points, max_vertices = 1) out;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Geometry Shaders allow 'invocations' declared together with input primitives in one layout.
TEST_F(GeometryShaderTest, InvocationsDeclaredWithInputPrimitives)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points, invocations = 3) in;\n"
"layout (points, max_vertices = 1) out;\n"
"void main()\n"
"{\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Geometry Shaders allow 'invocations' declared before input primitives in one input layout.
TEST_F(GeometryShaderTest, InvocationsBeforeInputPrimitives)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (invocations = 3, points) in;\n"
"layout (points, max_vertices = 1) out;\n"
"void main()\n"
"{\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Geometry Shaders allow 'invocations' declared in an individual input layout.
TEST_F(GeometryShaderTest, InvocationsInIndividualLayout)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points) in;\n"
"layout (invocations = 3) in;\n"
"layout (points, max_vertices = 1) out;\n"
"void main()\n"
"{\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Geometry Shaders allow duplicated 'invocations' declarations.
TEST_F(GeometryShaderTest, DuplicatedInvocations)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points, invocations = 3) in;\n"
"layout (invocations = 3) in;\n"
"layout (points, max_vertices = 1) out;\n"
"void main()\n"
"{\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Geometry Shaders don't allow multiple different 'invocations' declarations in different
// layouts.
TEST_F(GeometryShaderTest, RedeclareDifferentInvocations)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points, invocations = 3) in;\n"
"layout (invocations = 5) in;\n"
"layout (points, max_vertices = 1) out;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Geometry Shaders don't allow multiple different 'invocations' declarations in different
// layouts.
TEST_F(GeometryShaderTest, RedeclareDifferentInvocationsAfterInvocationEqualsOne)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points, invocations = 1) in;\n"
"layout (invocations = 5) in;\n"
"layout (points, max_vertices = 1) out;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Geometry Shaders don't allow multiple different 'invocations' declarations in one layout.
TEST_F(GeometryShaderTest, RedeclareDifferentInvocationsInOneLayout)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points, invocations = 3, invocations = 5) in;\n"
"layout (points, max_vertices = 1) out;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Geometry Shaders don't allow 'invocations' in out layouts.
TEST_F(GeometryShaderTest, DeclareInvocationsInOutLayout)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points) in;\n"
"layout (points, invocations = 3, max_vertices = 1) out;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Geometry Shaders don't allow 'invocations' in layouts without 'in' qualifier.
TEST_F(GeometryShaderTest, DeclareInvocationsInLayoutNoQualifier)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points) in;\n"
"layout (invocations = 3);\n"
"layout (points, max_vertices = 1) out;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Geometry Shaders allow declaring output primitive before input primitive declaration.
TEST_F(GeometryShaderTest, DeclareOutputPrimitiveBeforeInputPrimitiveDeclare)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points, max_vertices = 1) out;\n"
"layout (points) in;\n"
"void main()\n"
"{\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Geometry Shaders allow declaring 'max_vertices' before output primitive in one output layout.
TEST_F(GeometryShaderTest, DeclareMaxVerticesBeforeOutputPrimitive)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points) in;\n"
"layout (max_vertices = 1, points) out;\n"
"void main()\n"
"{\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Missing the declaration of output primitive should be a link error instead of a compile error in
// a geometry shader.
TEST_F(GeometryShaderTest, NoOutputPrimitives)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points) in;\n"
"layout (max_vertices = 1) out;\n"
"void main()\n"
"{\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Geometry Shaders can only support 3 kinds of output primitives, which cannot be used as input
// primitives except 'points'.
// Skip testing "points" as it can be used as both input and output primitives.
TEST_F(GeometryShaderTest, ValidateOutputPrimitives)
{
const std::string outputPrimitives[] = {"line_strip", "triangle_strip"};
for (const std::string &outPrimitive : outputPrimitives)
{
if (!compileGeometryShader(kInputLayout,
GetGeometryShaderLayout("out", outPrimitive, -1, 6)))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
if (compileGeometryShader(GetGeometryShaderLayout("in", outPrimitive, -1, -1),
kOutputLayout))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
}
// Geometry Shaders allow duplicated output primitive declarations, but all of them must be same.
TEST_F(GeometryShaderTest, RedeclareOutputPrimitives)
{
const std::array<std::string, 3> outPrimitives = {{"points", "line_strip", "triangle_strip"}};
for (GLuint i = 0; i < outPrimitives.size(); i++)
{
constexpr int maxVertices = 1;
const std::string &outputLayoutStr1 =
GetGeometryShaderLayout("out", outPrimitives[i], -1, maxVertices);
const std::string &outputLayoutStr2 =
GetGeometryShaderLayout("out", outPrimitives[i], -1, -1);
if (!compileGeometryShader(kInputLayout, outputLayoutStr1, outputLayoutStr2, ""))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
for (GLuint j = i + 1; j < outPrimitives.size(); j++)
{
const std::string &outputLayoutStr3 =
GetGeometryShaderLayout("out", outPrimitives[j], -1, -1);
if (compileGeometryShader(kInputLayout, outputLayoutStr1, outputLayoutStr3, ""))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
}
}
// Geometry Shaders don't allow declaring different output primitives in one layout.
TEST_F(GeometryShaderTest, RedeclareDifferentOutputPrimitivesInOneLayout)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points) in;\n"
"layout (points, max_vertices = 3, line_strip) out;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Missing the declarations of output primitives and 'max_vertices' in a geometry shader should
// be a link error instead of a compile error.
TEST_F(GeometryShaderTest, NoOutLayouts)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points) in;\n"
"void main()\n"
"{\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Missing the declarations of 'max_vertices' in a geometry shader should be a link error
// instead of a compile error.
TEST_F(GeometryShaderTest, NoMaxVertices)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points) in;\n"
"layout (points) out;\n"
"void main()\n"
"{\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Geometry Shaders cannot declare a negative 'max_vertices'.
TEST_F(GeometryShaderTest, NegativeMaxVertices)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points) in;\n"
"layout (points, max_vertices = -1) out;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Geometry Shaders allow max_vertices == 0.
TEST_F(GeometryShaderTest, ZeroMaxVertices)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points) in;\n"
"layout (points, max_vertices = 0) out;\n"
"void main()\n"
"{\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Geometry Shaders cannot declare a 'max_vertices' that is greater than
// MAX_GEOMETRY_OUTPUT_VERTICES_EXT (256 in this test).
TEST_F(GeometryShaderTest, TooLargeMaxVertices)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points) in;\n"
"layout (points, max_vertices = 257) out;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Geometry Shaders can declare 'max_vertices' in an individual out layout.
TEST_F(GeometryShaderTest, MaxVerticesInIndividualLayout)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points) in;\n"
"layout (points) out;\n"
"layout (max_vertices = 1) out;\n"
"void main()\n"
"{\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Geometry Shaders allow duplicated 'max_vertices' declarations.
TEST_F(GeometryShaderTest, DuplicatedMaxVertices)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points) in;\n"
"layout (points, max_vertices = 1) out;\n"
"layout (max_vertices = 1) out;\n"
"void main()\n"
"{\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Geometry Shaders don't allow declaring different 'max_vertices'.
TEST_F(GeometryShaderTest, RedeclareDifferentMaxVertices)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points) in;\n"
"layout (points, max_vertices = 1) out;\n"
"layout (max_vertices = 2) out;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Geometry Shaders don't allow declaring different 'max_vertices'.
TEST_F(GeometryShaderTest, RedeclareDifferentMaxVerticesInOneLayout)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points) in;\n"
"layout (points, max_vertices = 2, max_vertices = 1) out;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Geometry Shaders don't allow 'location' declared with input/output primitives in one layout.
TEST_F(GeometryShaderTest, invalidLocation)
{
const std::string &shaderString1 =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points, location = 1) 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, location = 1) 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, location = 3, 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, location = 3) out;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString1) || compile(shaderString2) || compile(shaderString3) ||
compile(shaderString4))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Geometry Shaders don't allow invalid layout qualifier declarations.
TEST_F(GeometryShaderTest, invalidLayoutQualifiers)
{
const std::string &shaderString1 =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points, abc) 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 (points, abc, 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, xyz = 2) in;\n"
"layout (points, 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, xyz = 3) out;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString1) || compile(shaderString2) || compile(shaderString3) ||
compile(shaderString4))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
...@@ -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