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 @@
// Version number for shader translation API.
// It is incremented every time the API changes.
#define ANGLE_SH_VERSION 178
#define ANGLE_SH_VERSION 179
enum ShShaderSpec
{
......@@ -291,6 +291,7 @@ struct ShBuiltInResources
int ARM_shader_framebuffer_fetch;
int OVR_multiview;
int EXT_YUV_target;
int OES_geometry_shader;
// 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
......@@ -411,6 +412,12 @@ struct ShBuiltInResources
// maximum point size (higher limit from ALIASED_POINT_SIZE_RANGE)
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)
resources->OES_standard_derivatives = 0;
resources->OES_EGL_image_external = 0;
resources->OES_geometry_shader = 1;
}
int main(int argc, char *argv[])
......@@ -74,6 +75,7 @@ int main(int argc, char *argv[])
ShHandle vertexCompiler = 0;
ShHandle fragmentCompiler = 0;
ShHandle computeCompiler = 0;
ShHandle geometryCompiler = 0;
ShShaderSpec spec = SH_GLES2_SPEC;
ShShaderOutput output = SH_ESSL_OUTPUT;
......@@ -268,7 +270,14 @@ int main(int argc, char *argv[])
}
compiler = computeCompiler;
break;
case GL_GEOMETRY_SHADER_OES:
if (geometryCompiler == 0)
{
geometryCompiler =
sh::ConstructCompiler(GL_GEOMETRY_SHADER_OES, spec, output, &resources);
}
compiler = geometryCompiler;
break;
default: break;
}
if (compiler)
......@@ -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;
if (failCode == EFailUsage)
usage();
......@@ -318,6 +328,8 @@ int main(int argc, char *argv[])
sh::Destruct(fragmentCompiler);
if (computeCompiler)
sh::Destruct(computeCompiler);
if (geometryCompiler)
sh::Destruct(geometryCompiler);
sh::Finalize();
......@@ -389,6 +401,8 @@ sh::GLenum FindShaderType(const char *fileName)
return GL_VERTEX_SHADER;
if (strncmp(ext, ".comp", 5) == 0)
return GL_COMPUTE_SHADER;
if (strncmp(ext, ".geom", 5) == 0)
return GL_GEOMETRY_SHADER_OES;
}
return GL_FRAGMENT_SHADER;
......
......@@ -573,6 +573,10 @@ enum TQualifier
EvqRestrict,
EvqVolatile,
// GLSL ES 3.1 extension OES_geometry_shader qualifiers
EvqGeometryIn,
EvqGeometryOut,
// end of list
EvqLast
};
......@@ -623,6 +627,18 @@ enum TYuvCscStandardEXT
EycsItu709
};
enum TLayoutPrimitiveType
{
EptUndefined,
EptPoints,
EptLines,
EptLinesAdjacency,
EptTriangles,
EptTrianglesAdjacency,
EptLineStrip,
EptTriangleStrip
};
struct TLayoutQualifier
{
int location;
......@@ -645,6 +661,11 @@ struct TLayoutQualifier
// EXT_YUV_target yuv layout qualifier.
bool yuv;
// OES_geometry_shader layout qualifiers.
TLayoutPrimitiveType primitiveType;
int invocations;
int maxVertices;
static TLayoutQualifier create()
{
TLayoutQualifier layoutQualifier;
......@@ -661,6 +682,11 @@ struct TLayoutQualifier
layoutQualifier.yuv = false;
layoutQualifier.imageInternalFormat = EiifUnspecified;
layoutQualifier.primitiveType = EptUndefined;
layoutQualifier.invocations = 0;
layoutQualifier.maxVertices = -1;
return layoutQualifier;
}
......@@ -668,13 +694,16 @@ struct TLayoutQualifier
{
return location == -1 && binding == -1 && offset == -1 && numViews == -1 && yuv == false &&
matrixPacking == EmpUnspecified && blockStorage == EbsUnspecified &&
!localSize.isAnyValueSet() && imageInternalFormat == EiifUnspecified;
!localSize.isAnyValueSet() && imageInternalFormat == EiifUnspecified &&
primitiveType == EptUndefined && invocations == 0 && maxVertices == -1;
}
bool isCombinationValid() const
{
bool workSizeSpecified = localSize.isAnyValueSet();
bool numViewsSet = (numViews != -1);
bool geometryShaderSpecified =
(primitiveType != EptUndefined) || (invocations != 0) || (maxVertices != -1);
bool otherLayoutQualifiersSpecified =
(location != -1 || binding != -1 || matrixPacking != EmpUnspecified ||
blockStorage != EbsUnspecified || imageInternalFormat != EiifUnspecified);
......@@ -682,7 +711,7 @@ struct TLayoutQualifier
// we can have either the work group size specified, or number of views,
// or yuv layout qualifier, or the other layout qualifiers.
return (workSizeSpecified ? 1 : 0) + (numViewsSet ? 1 : 0) + (yuv ? 1 : 0) +
(otherLayoutQualifiersSpecified ? 1 : 0) <=
(otherLayoutQualifiersSpecified ? 1 : 0) + (geometryShaderSpecified ? 1 : 0) <=
1;
}
......@@ -799,6 +828,8 @@ inline const char *getQualifierString(TQualifier q)
case EvqLocalInvocationIndex: return "LocalInvocationIndex";
case EvqReadOnly: return "readonly";
case EvqWriteOnly: return "writeonly";
case EvqGeometryIn: return "in";
case EvqGeometryOut: return "out";
default: UNREACHABLE(); return "unknown qualifier";
}
// clang-format on
......@@ -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
#endif // COMPILER_TRANSLATOR_BASETYPES_H_
......@@ -146,11 +146,14 @@ int GetMaxUniformVectorsForShaderType(GLenum shaderType, const ShBuiltInResource
return resources.MaxVertexUniformVectors;
case GL_FRAGMENT_SHADER:
return resources.MaxFragmentUniformVectors;
// TODO (jiawei.shao@intel.com): check if we need finer-grained component counting
case GL_COMPUTE_SHADER:
// TODO (jiawei.shao@intel.com): check if we need finer-grained component counting
return resources.MaxComputeUniformComponents / 4;
case GL_GEOMETRY_SHADER_OES:
return resources.MaxGeometryUniformComponents / 4;
default:
UNIMPLEMENTED();
UNREACHABLE();
return -1;
}
}
......@@ -242,7 +245,11 @@ TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
builtInFunctionEmulator(),
mDiagnostics(infoSink.info),
mSourcePath(nullptr),
mComputeShaderLocalSizeDeclared(false)
mComputeShaderLocalSizeDeclared(false),
mGeometryShaderMaxVertices(-1),
mGeometryShaderInvocations(0),
mGeometryShaderInputPrimitiveType(EptUndefined),
mGeometryShaderOutputPrimitiveType(EptUndefined)
{
mComputeShaderLocalSize.fill(1);
}
......@@ -360,6 +367,15 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
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.
if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY))
success = limitExpressionComplexity(root);
......@@ -626,15 +642,13 @@ bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources &resources)
symbolTable.setDefaultPrecision(EbtInt, EbpMedium);
break;
case GL_VERTEX_SHADER:
symbolTable.setDefaultPrecision(EbtInt, EbpHigh);
symbolTable.setDefaultPrecision(EbtFloat, EbpHigh);
break;
case GL_COMPUTE_SHADER:
case GL_GEOMETRY_SHADER_OES:
symbolTable.setDefaultPrecision(EbtInt, EbpHigh);
symbolTable.setDefaultPrecision(EbtFloat, EbpHigh);
break;
default:
assert(false && "Language not supported");
UNREACHABLE();
}
// Set defaults for sampler types that have default precision, even those that are
// only available if an extension exists.
......@@ -694,6 +708,7 @@ void TCompiler::setResourceString()
<< ":ARM_shader_framebuffer_fetch:" << compileResources.ARM_shader_framebuffer_fetch
<< ":OVR_multiview:" << compileResources.OVR_multiview
<< ":EXT_YUV_target:" << compileResources.EXT_YUV_target
<< ":OES_geometry_shader:" << compileResources.OES_geometry_shader
<< ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors
<< ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors
<< ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset
......@@ -725,7 +740,10 @@ void TCompiler::setResourceString()
<< ":MaxVertexAtomicCounterBuffers:" << compileResources.MaxVertexAtomicCounterBuffers
<< ":MaxFragmentAtomicCounterBuffers:" << compileResources.MaxFragmentAtomicCounterBuffers
<< ":MaxCombinedAtomicCounterBuffers:" << compileResources.MaxCombinedAtomicCounterBuffers
<< ":MaxAtomicCounterBufferSize:" << compileResources.MaxAtomicCounterBufferSize;
<< ":MaxAtomicCounterBufferSize:" << compileResources.MaxAtomicCounterBufferSize
<< ":MaxGeometryOutputVertices:" << compileResources.MaxGeometryOutputVertices
<< ":MaxGeometryUniformComponents:" << compileResources.MaxGeometryUniformComponents
<< ":MaxGeometryShaderInvocations:" << compileResources.MaxGeometryShaderInvocations;
// clang-format on
builtInResourcesString = strstream.str();
......@@ -749,6 +767,11 @@ void TCompiler::clearResults()
mNumViews = -1;
mGeometryShaderInputPrimitiveType = EptUndefined;
mGeometryShaderOutputPrimitiveType = EptUndefined;
mGeometryShaderInvocations = 0;
mGeometryShaderMaxVertices = -1;
builtInFunctionEmulator.cleanup();
nameMap.clear();
......
......@@ -125,8 +125,20 @@ class TCompiler : public TShHandleBase
// Get the resources set by InitBuiltInSymbolTable
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; }
protected:
// Initialize symbol-table with built-in symbols.
bool InitBuiltInSymbolTable(const ShBuiltInResources &resources);
// Compute the string representation of the built-in resources
......@@ -241,6 +253,12 @@ class TCompiler : public TShHandleBase
// GL_OVR_multiview num_views.
int mNumViews;
// geometry shader parameters.
int mGeometryShaderMaxVertices;
int mGeometryShaderInvocations;
TLayoutPrimitiveType mGeometryShaderInputPrimitiveType;
TLayoutPrimitiveType mGeometryShaderOutputPrimitiveType;
// name hashing.
ShHashFunction64 hashFunction;
NameMap nameMap;
......
......@@ -902,6 +902,10 @@ void IdentifyBuiltIns(sh::GLenum type,
}
break;
case GL_GEOMETRY_SHADER_OES:
// TODO(jiawei.shao@intel.com): add Geometry Shader built-in variables.
break;
default:
assert(false && "Language not supported");
}
......@@ -942,6 +946,10 @@ void InitExtensionBehavior(const ShBuiltInResources &resources, TExtensionBehavi
{
extBehavior["GL_EXT_YUV_target"] = EBhUndefined;
}
if (resources.OES_geometry_shader)
{
extBehavior["GL_OES_geometry_shader"] = EBhUndefined;
}
}
void ResetExtensionBehavior(TExtensionBehavior &extBehavior)
......
......@@ -6,6 +6,7 @@
#include "compiler/translator/OutputGLSLBase.h"
#include "angle_gl.h"
#include "common/debug.h"
#include "common/mathutil.h"
#include "compiler/translator/Compiler.h"
......@@ -1293,4 +1294,52 @@ void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBloc
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
......@@ -109,6 +109,12 @@ class TOutputGLSLBase : public TIntermTraverser
ShCompileOptions mCompileOptions;
};
void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out,
sh::TLayoutPrimitiveType inputPrimitive,
int invocations,
sh::TLayoutPrimitiveType outputPrimitive,
int maxVertices);
} // namespace sh
#endif // COMPILER_TRANSLATOR_OUTPUTGLSLBASE_H_
......@@ -340,6 +340,14 @@ class TParseContext : angle::NonCopyable
const TSourceLoc &intValueLine,
const std::string &intValueString,
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,
const TSourceLoc &qualifierTypeLine);
TLayoutQualifier parseLayoutQualifier(const TString &qualifierType,
......@@ -407,6 +415,20 @@ class TParseContext : angle::NonCopyable
TIntermTyped *falseExpression,
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
TSymbolTable &symbolTable; // symbol table that goes with the language currently being parsed
......@@ -510,6 +532,10 @@ class TParseContext : angle::NonCopyable
void setAtomicCounterBindingDefaultOffset(const TPublicType &declaration,
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
// non-empty declaration error check will need to be performed if the empty declaration is
// followed by a declarator.
......@@ -566,6 +592,14 @@ class TParseContext : angle::NonCopyable
// Track the state of each atomic counter binding.
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,
......
......@@ -606,6 +606,42 @@ TLayoutQualifier JoinLayoutQualifiers(TLayoutQualifier leftQualifier,
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;
}
......
......@@ -164,6 +164,7 @@ void InitBuiltInResources(ShBuiltInResources *resources)
resources->ARM_shader_framebuffer_fetch = 0;
resources->OVR_multiview = 0;
resources->EXT_YUV_target = 0;
resources->OES_geometry_shader = 0;
resources->NV_draw_buffers = 0;
......@@ -224,6 +225,11 @@ void InitBuiltInResources(ShBuiltInResources *resources)
resources->MaxAtomicCounterBufferSize = 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
<< ", local_size_z=" << localSize[2] << ") in;\n";
}
if (getShaderType() == GL_GEOMETRY_SHADER_OES)
{
WriteGeometryShaderLayoutQualifiers(
sink, getGeometryShaderInputPrimitiveType(), getGeometryShaderInvocations(),
getGeometryShaderOutputPrimitiveType(), getGeometryShaderMaxVertices());
}
// Write translated shader.
TOutputESSL outputESSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(),
&getSymbolTable(), getShaderType(), shaderVer, precisionEmulation,
......@@ -153,6 +160,22 @@ void TranslatorESSL::writeExtensionBehavior(ShCompileOptions compileOptions)
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
{
sink << "#extension " << iter->first << " : " << getBehaviorString(iter->second)
......
......@@ -200,6 +200,13 @@ void TranslatorGLSL::translate(TIntermBlock *root, ShCompileOptions compileOptio
<< ", local_size_z=" << localSize[2] << ") in;\n";
}
if (getShaderType() == GL_GEOMETRY_SHADER_OES)
{
WriteGeometryShaderLayoutQualifiers(
sink, getGeometryShaderInputPrimitiveType(), getGeometryShaderInvocations(),
getGeometryShaderOutputPrimitiveType(), getGeometryShaderMaxVertices());
}
// Write translated shader.
TOutputGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(),
&getSymbolTable(), getShaderType(), getShaderVersion(), getOutputType(),
......@@ -268,6 +275,12 @@ void TranslatorGLSL::writeExtensionBehavior(TIntermNode *root, ShCompileOptions
sink << "#extension GL_ARB_draw_buffers : " << getBehaviorString(iter.second)
<< "\n";
}
if (iter.first == "GL_OES_geometry_shader")
{
sink << "#extension GL_ARB_geometry_shader4 : " << getBehaviorString(iter.second)
<< "\n";
}
}
const bool isMultiview =
......
......@@ -64,6 +64,7 @@
'<(angle_path)/src/tests/compiler_tests/FloatLex_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/GeometryShader_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/NV_draw_buffers_test.cpp',
......
......@@ -93,6 +93,20 @@ class ComputeShaderEnforcePackingValidationTest : public ComputeShaderValidation
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:
// Calling a function with all parameters missing should not succeed.
TEST_F(FragmentShaderValidationTest, FunctionParameterMismatch)
......@@ -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
// the local size has not been declared yet.
// GLSL ES 3.10 Revision 4, 7.1.3 Compute Shader Special Variables
......@@ -4086,3 +4147,180 @@ TEST_F(FragmentShaderValidationTest, ArrayAsArraySize)
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