Commit d27f5c8d by Jiawei Shao Committed by Commit Bot

ES31: Implement GL_OES_geometry_shader built-ins in GLSL compiler

This patch intends to implement all built-in constants, variables and functions defined in OpenGL ES 3.1 extension GL_OES_geometry_shader in ANGLE GLSL compiler. 1. Add all built-in constants defined in GL_OES_geometry_shader. 2. Add built-in functions EmitVertex() and EndPrimitive() required in Geometry Shader. 3. Add built-in variables gl_PrimitiveIDIn and gl_InvocationID to Geometry Shader. 4. Add built-in variables gl_PrimitiveID and gl_Layer to both Geometry Shader and Fragment Shader when GL_OES_geometry_shader is enabled. BUG=angleproject:1941 TEST=angle_unittests Change-Id: I92821553ed0efee2ccb77fead6e065e7799819d0 Reviewed-on: https://chromium-review.googlesource.com/627670 Commit-Queue: Corentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 3c25ad07
......@@ -25,7 +25,7 @@
// Version number for shader translation API.
// It is incremented every time the API changes.
#define ANGLE_SH_VERSION 179
#define ANGLE_SH_VERSION 180
enum ShShaderSpec
{
......@@ -415,10 +415,18 @@ struct ShBuiltInResources
float MaxPointSize;
// OES_geometry_shader constants
// TODO(jiawei.shao@intel.com): add complete geometry shader constants.
int MaxGeometryUniformComponents;
int MaxGeometryUniformBlocks;
int MaxGeometryInputComponents;
int MaxGeometryOutputComponents;
int MaxGeometryOutputVertices;
int MaxGeometryTotalOutputComponents;
int MaxGeometryTextureImageUnits;
int MaxGeometryAtomicCounterBuffers;
int MaxGeometryAtomicCounters;
int MaxGeometryShaderStorageBlocks;
int MaxGeometryShaderInvocations;
int MaxGeometryImageUniforms;
};
//
......
......@@ -576,8 +576,11 @@ enum TQualifier
// GLSL ES 3.1 extension OES_geometry_shader qualifiers
EvqGeometryIn,
EvqGeometryOut,
EvqPerVertexIn,
EvqLayer, // gl_Layer
EvqPerVertexIn, // gl_in
EvqPrimitiveIDIn, // gl_PrimitiveIDIn
EvqInvocationID, // gl_InvocationID
EvqPrimitiveID, // gl_PrimitiveID
EvqLayer, // gl_Layer
// end of list
EvqLast
......
......@@ -100,6 +100,7 @@ class CollectVariablesTraverser : public TIntermTraverser
ShHashFunction64 hashFunction,
TSymbolTable *symbolTable,
int shaderVersion,
GLenum shaderType,
const TExtensionBehavior &extensionBehavior);
void visitSymbol(TIntermSymbol *symbol) override;
......@@ -139,15 +140,21 @@ class CollectVariablesTraverser : public TIntermTraverser
std::map<std::string, InterfaceBlockField *> mInterfaceBlockFields;
// Shader uniforms
bool mDepthRangeAdded;
bool mPointCoordAdded;
bool mFrontFacingAdded;
bool mFragCoordAdded;
// Vertex Shader builtins
bool mInstanceIDAdded;
bool mVertexIDAdded;
bool mPositionAdded;
bool mPointSizeAdded;
// Vertex Shader and Geometry Shader builtins
bool mPositionAdded;
// Fragment Shader builtins
bool mPointCoordAdded;
bool mFrontFacingAdded;
bool mFragCoordAdded;
bool mLastFragDataAdded;
bool mFragColorAdded;
bool mFragDataAdded;
......@@ -156,11 +163,19 @@ class CollectVariablesTraverser : public TIntermTraverser
bool mSecondaryFragColorEXTAdded;
bool mSecondaryFragDataEXTAdded;
// Geometry Shader builtins
bool mPerVertexInAdded;
bool mPrimitiveIDInAdded;
bool mInvocationIDAdded;
// Geometry Shader and Fragment Shader builtins
bool mPrimitiveIDAdded;
bool mLayerAdded;
ShHashFunction64 mHashFunction;
int mShaderVersion;
GLenum mShaderType;
const TExtensionBehavior &mExtensionBehavior;
};
......@@ -176,6 +191,7 @@ CollectVariablesTraverser::CollectVariablesTraverser(
ShHashFunction64 hashFunction,
TSymbolTable *symbolTable,
int shaderVersion,
GLenum shaderType,
const TExtensionBehavior &extensionBehavior)
: TIntermTraverser(true, false, false, symbolTable),
mAttribs(attribs),
......@@ -187,13 +203,13 @@ CollectVariablesTraverser::CollectVariablesTraverser(
mShaderStorageBlocks(shaderStorageBlocks),
mInBlocks(inBlocks),
mDepthRangeAdded(false),
mPointCoordAdded(false),
mFrontFacingAdded(false),
mFragCoordAdded(false),
mInstanceIDAdded(false),
mVertexIDAdded(false),
mPositionAdded(false),
mPointSizeAdded(false),
mPositionAdded(false),
mPointCoordAdded(false),
mFrontFacingAdded(false),
mFragCoordAdded(false),
mLastFragDataAdded(false),
mFragColorAdded(false),
mFragDataAdded(false),
......@@ -202,8 +218,13 @@ CollectVariablesTraverser::CollectVariablesTraverser(
mSecondaryFragColorEXTAdded(false),
mSecondaryFragDataEXTAdded(false),
mPerVertexInAdded(false),
mPrimitiveIDInAdded(false),
mInvocationIDAdded(false),
mPrimitiveIDAdded(false),
mLayerAdded(false),
mHashFunction(hashFunction),
mShaderVersion(shaderVersion),
mShaderType(shaderType),
mExtensionBehavior(extensionBehavior)
{
}
......@@ -470,6 +491,38 @@ void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol)
recordBuiltInFragmentOutputUsed("gl_SecondaryFragDataEXT",
&mSecondaryFragDataEXTAdded);
return;
case EvqInvocationID:
recordBuiltInVaryingUsed("gl_InvocationID", &mInvocationIDAdded, mInputVaryings);
break;
case EvqPrimitiveIDIn:
recordBuiltInVaryingUsed("gl_PrimitiveIDIn", &mPrimitiveIDInAdded, mInputVaryings);
break;
case EvqPrimitiveID:
if (mShaderType == GL_GEOMETRY_SHADER_OES)
{
recordBuiltInVaryingUsed("gl_PrimitiveID", &mPrimitiveIDAdded, mOutputVaryings);
}
else
{
ASSERT(mShaderType == GL_FRAGMENT_SHADER);
recordBuiltInVaryingUsed("gl_PrimitiveID", &mPrimitiveIDAdded, mInputVaryings);
}
break;
case EvqLayer:
if (mShaderType == GL_GEOMETRY_SHADER_OES)
{
recordBuiltInVaryingUsed("gl_Layer", &mLayerAdded, mOutputVaryings);
}
else if (mShaderType == GL_FRAGMENT_SHADER)
{
recordBuiltInVaryingUsed("gl_Layer", &mLayerAdded, mInputVaryings);
}
else
{
ASSERT(mShaderType == GL_VERTEX_SHADER &&
IsExtensionEnabled(mExtensionBehavior, "GL_OVR_multiview"));
}
break;
default:
break;
}
......@@ -783,11 +836,13 @@ void CollectVariables(TIntermBlock *root,
ShHashFunction64 hashFunction,
TSymbolTable *symbolTable,
int shaderVersion,
GLenum shaderType,
const TExtensionBehavior &extensionBehavior)
{
CollectVariablesTraverser collect(attributes, outputVariables, uniforms, inputVaryings,
outputVaryings, uniformBlocks, shaderStorageBlocks, inBlocks,
hashFunction, symbolTable, shaderVersion, extensionBehavior);
hashFunction, symbolTable, shaderVersion, shaderType,
extensionBehavior);
root->traverse(&collect);
}
......
......@@ -30,6 +30,7 @@ void CollectVariables(TIntermBlock *root,
ShHashFunction64 hashFunction,
TSymbolTable *symbolTable,
int shaderVersion,
GLenum shaderType,
const TExtensionBehavior &extensionBehavior);
}
......
......@@ -476,7 +476,8 @@ TIntermBlock *TCompiler::compileTreeImpl(const char *const shaderStrings[],
ASSERT(!variablesCollected);
CollectVariables(root, &attributes, &outputVariables, &uniforms, &inputVaryings,
&outputVaryings, &uniformBlocks, &shaderStorageBlocks, &inBlocks,
hashFunction, &symbolTable, shaderVersion, extensionBehavior);
hashFunction, &symbolTable, shaderVersion, shaderType,
extensionBehavior);
collectInterfaceBlocks();
variablesCollected = true;
if (compileOptions & SH_USE_UNUSED_STANDARD_SHARED_BLOCKS)
......@@ -740,9 +741,18 @@ void TCompiler::setResourceString()
<< ":MaxFragmentAtomicCounterBuffers:" << compileResources.MaxFragmentAtomicCounterBuffers
<< ":MaxCombinedAtomicCounterBuffers:" << compileResources.MaxCombinedAtomicCounterBuffers
<< ":MaxAtomicCounterBufferSize:" << compileResources.MaxAtomicCounterBufferSize
<< ":MaxGeometryOutputVertices:" << compileResources.MaxGeometryOutputVertices
<< ":MaxGeometryUniformComponents:" << compileResources.MaxGeometryUniformComponents
<< ":MaxGeometryShaderInvocations:" << compileResources.MaxGeometryShaderInvocations;
<< ":MaxGeometryUniformBlocks:" << compileResources.MaxGeometryUniformBlocks
<< ":MaxGeometryInputComponents:" << compileResources.MaxGeometryInputComponents
<< ":MaxGeometryOutputComponents:" << compileResources.MaxGeometryOutputComponents
<< ":MaxGeometryOutputVertices:" << compileResources.MaxGeometryOutputVertices
<< ":MaxGeometryTotalOutputComponents:" << compileResources.MaxGeometryTotalOutputComponents
<< ":MaxGeometryTextureImageUnits:" << compileResources.MaxGeometryTextureImageUnits
<< ":MaxGeometryAtomicCounterBuffers:" << compileResources.MaxGeometryAtomicCounterBuffers
<< ":MaxGeometryAtomicCounters:" << compileResources.MaxGeometryAtomicCounters
<< ":MaxGeometryShaderStorageBlocks:" << compileResources.MaxGeometryShaderStorageBlocks
<< ":MaxGeometryShaderInvocations:" << compileResources.MaxGeometryShaderInvocations
<< ":MaxGeometryImageUniforms:" << compileResources.MaxGeometryImageUniforms;
// clang-format on
builtInResourcesString = strstream.str();
......@@ -1010,7 +1020,7 @@ void TCompiler::useAllMembersInUnusedStandardAndSharedBlocks(TIntermBlock *root)
void TCompiler::initializeOutputVariables(TIntermBlock *root)
{
InitVariableList list;
if (shaderType == GL_VERTEX_SHADER)
if (shaderType == GL_VERTEX_SHADER || shaderType == GL_GEOMETRY_SHADER_OES)
{
for (auto var : outputVaryings)
{
......
......@@ -676,6 +676,15 @@ void InsertBuiltInFunctions(sh::GLenum type,
voidType, "groupMemoryBarrier");
}
if (type == GL_GEOMETRY_SHADER_OES)
{
const char *extension = "GL_OES_geometry_shader";
symbolTable.insertBuiltInFunctionNoParametersExt(ESSL3_1_BUILTINS, extension, EOpEmitVertex,
voidType, "EmitVertex");
symbolTable.insertBuiltInFunctionNoParametersExt(ESSL3_1_BUILTINS, extension,
EOpEndPrimitive, voidType, "EndPrimitive");
}
//
// Depth range in window coordinates
//
......@@ -720,7 +729,7 @@ void InsertBuiltInFunctions(sh::GLenum type,
{
symbolTable.insertConstIntExt(COMMON_BUILTINS, "GL_EXT_blend_func_extended",
"gl_MaxDualSourceDrawBuffersEXT",
resources.MaxDualSourceDrawBuffers);
resources.MaxDualSourceDrawBuffers, EbpMedium);
}
symbolTable.insertConstInt(ESSL3_BUILTINS, "gl_MaxVertexOutputVectors",
......@@ -777,6 +786,29 @@ void InsertBuiltInFunctions(sh::GLenum type,
resources.MaxCombinedAtomicCounterBuffers, EbpMedium);
symbolTable.insertConstInt(ESSL3_1_BUILTINS, "gl_MaxAtomicCounterBufferSize",
resources.MaxAtomicCounterBufferSize, EbpMedium);
if (resources.OES_geometry_shader)
{
const char *ext = "GL_OES_geometry_shader";
symbolTable.insertConstIntExt(ESSL3_1_BUILTINS, ext, "gl_MaxGeometryInputComponents",
resources.MaxGeometryInputComponents, EbpMedium);
symbolTable.insertConstIntExt(ESSL3_1_BUILTINS, ext, "gl_MaxGeometryOutputComponents",
resources.MaxGeometryOutputComponents, EbpMedium);
symbolTable.insertConstIntExt(ESSL3_1_BUILTINS, ext, "gl_MaxGeometryImageUniforms",
resources.MaxGeometryImageUniforms, EbpMedium);
symbolTable.insertConstIntExt(ESSL3_1_BUILTINS, ext, "gl_MaxGeometryTextureImageUnits",
resources.MaxGeometryTextureImageUnits, EbpMedium);
symbolTable.insertConstIntExt(ESSL3_1_BUILTINS, ext, "gl_MaxGeometryOutputVertices",
resources.MaxGeometryOutputVertices, EbpMedium);
symbolTable.insertConstIntExt(ESSL3_1_BUILTINS, ext, "gl_MaxGeometryTotalOutputComponents",
resources.MaxGeometryTotalOutputComponents, EbpMedium);
symbolTable.insertConstIntExt(ESSL3_1_BUILTINS, ext, "gl_MaxGeometryUniformComponents",
resources.MaxGeometryUniformComponents, EbpMedium);
symbolTable.insertConstIntExt(ESSL3_1_BUILTINS, ext, "gl_MaxGeometryAtomicCounters",
resources.MaxGeometryAtomicCounters, EbpMedium);
symbolTable.insertConstIntExt(ESSL3_1_BUILTINS, ext, "gl_MaxGeometryAtomicCounterBuffers",
resources.MaxGeometryAtomicCounterBuffers, EbpMedium);
}
}
void IdentifyBuiltIns(sh::GLenum type,
......@@ -872,6 +904,15 @@ void IdentifyBuiltIns(sh::GLenum type,
TType(EbtFloat, EbpMedium, EvqLastFragColor, 4));
}
if (resources.OES_geometry_shader)
{
const char *extension = "GL_OES_geometry_shader";
symbolTable.insertVariableExt(ESSL3_1_BUILTINS, extension, "gl_PrimitiveID",
TType(EbtInt, EbpHigh, EvqPrimitiveID, 1));
symbolTable.insertVariableExt(ESSL3_1_BUILTINS, extension, "gl_Layer",
TType(EbtInt, EbpHigh, EvqLayer, 1));
}
break;
}
case GL_VERTEX_SHADER:
......@@ -909,7 +950,6 @@ void IdentifyBuiltIns(sh::GLenum type,
case GL_GEOMETRY_SHADER_OES:
{
// TODO(jiawei.shao@intel.com): add all Geometry Shader built-in variables.
const char *extension = "GL_OES_geometry_shader";
// Add built-in interface block gl_PerVertex and the built-in array gl_in.
......@@ -932,6 +972,20 @@ void IdentifyBuiltIns(sh::GLenum type,
glInType.makeArray(0u);
symbolTable.insertVariableExt(ESSL3_1_BUILTINS, extension, "gl_in", glInType);
TType glPositionType(EbtFloat, EbpHigh, EvqPosition, 4);
glPositionType.setInterfaceBlock(new TInterfaceBlock(
glPerVertexString, fieldList, nullptr, TLayoutQualifier::create()));
symbolTable.insertVariableExt(ESSL3_1_BUILTINS, extension, "gl_Position",
glPositionType);
symbolTable.insertVariableExt(ESSL3_1_BUILTINS, extension, "gl_PrimitiveIDIn",
TType(EbtInt, EbpHigh, EvqPrimitiveIDIn, 1));
symbolTable.insertVariableExt(ESSL3_1_BUILTINS, extension, "gl_InvocationID",
TType(EbtInt, EbpHigh, EvqInvocationID, 1));
symbolTable.insertVariableExt(ESSL3_1_BUILTINS, extension, "gl_PrimitiveID",
TType(EbtInt, EbpHigh, EvqPrimitiveID, 1));
symbolTable.insertVariableExt(ESSL3_1_BUILTINS, extension, "gl_Layer",
TType(EbtInt, EbpHigh, EvqLayer, 1));
break;
}
default:
......
......@@ -341,6 +341,11 @@ const char *GetOperatorString(TOperator op)
return "memoryBarrierShared";
case EOpGroupMemoryBarrier:
return "groupMemoryBarrier";
case EOpEmitVertex:
return "EmitVertex";
case EOpEndPrimitive:
return "EndPrimitive";
default:
break;
}
......
......@@ -237,7 +237,11 @@ enum TOperator
EOpMemoryBarrierBuffer,
EOpMemoryBarrierImage,
EOpMemoryBarrierShared,
EOpGroupMemoryBarrier
EOpGroupMemoryBarrier,
// Geometry only
EOpEmitVertex,
EOpEndPrimitive
};
// Returns the string corresponding to the operator in GLSL
......
......@@ -1006,6 +1006,8 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
case EOpMemoryBarrierImage:
case EOpMemoryBarrierShared:
case EOpGroupMemoryBarrier:
case EOpEmitVertex:
case EOpEndPrimitive:
writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
break;
default:
......
......@@ -521,6 +521,24 @@ bool TParseContext::checkCanBeLValue(const TSourceLoc &line, const char *op, TIn
case EvqPerVertexIn:
message = "can't modify any member in gl_in";
break;
case EvqPrimitiveIDIn:
message = "can't modify gl_PrimitiveIDIn";
break;
case EvqInvocationID:
message = "can't modify gl_InvocationID";
break;
case EvqPrimitiveID:
if (mShaderType == GL_FRAGMENT_SHADER)
{
message = "can't modify gl_PrimitiveID in a fragment shader";
}
break;
case EvqLayer:
if (mShaderType == GL_FRAGMENT_SHADER)
{
message = "can't modify gl_Layer in a fragment shader";
}
break;
default:
//
// Type that can't be written to?
......
......@@ -236,10 +236,18 @@ void InitBuiltInResources(ShBuiltInResources *resources)
resources->MaxUniformBufferBindings = 32;
// TODO(jiawei.shao@intel.com): add complete geometry shader constants.
resources->MaxGeometryUniformComponents = 1024;
resources->MaxGeometryOutputVertices = 256;
resources->MaxGeometryShaderInvocations = 32;
resources->MaxGeometryUniformComponents = 1024;
resources->MaxGeometryUniformBlocks = 12;
resources->MaxGeometryInputComponents = 64;
resources->MaxGeometryOutputComponents = 64;
resources->MaxGeometryOutputVertices = 256;
resources->MaxGeometryTotalOutputComponents = 1024;
resources->MaxGeometryTextureImageUnits = 16;
resources->MaxGeometryAtomicCounterBuffers = 0;
resources->MaxGeometryAtomicCounters = 0;
resources->MaxGeometryShaderStorageBlocks = 0;
resources->MaxGeometryShaderInvocations = 32;
resources->MaxGeometryImageUniforms = 0;
}
//
......@@ -365,7 +373,7 @@ const std::vector<Uniform> *GetUniforms(const ShHandle handle)
return GetShaderVariables<Uniform>(handle);
}
const std::vector<sh::Varying> *GetInputVaryings(const ShHandle handle)
const std::vector<Varying> *GetInputVaryings(const ShHandle handle)
{
TCompiler *compiler = GetCompilerFromHandle(handle);
if (compiler == nullptr)
......@@ -375,7 +383,7 @@ const std::vector<sh::Varying> *GetInputVaryings(const ShHandle handle)
return &compiler->getInputVaryings();
}
const std::vector<sh::Varying> *GetOutputVaryings(const ShHandle handle)
const std::vector<Varying> *GetOutputVaryings(const ShHandle handle)
{
TCompiler *compiler = GetCompilerFromHandle(handle);
if (compiler == nullptr)
......
......@@ -557,6 +557,16 @@ void TSymbolTable::insertBuiltInFunctionNoParameters(ESymbolLevel level,
insert(level, new TFunction(this, NewPoolTString(name), rvalue, op));
}
void TSymbolTable::insertBuiltInFunctionNoParametersExt(ESymbolLevel level,
const char *ext,
TOperator op,
const TType *rvalue,
const char *name)
{
insertUnmangledBuiltInName(name, level);
insert(level, new TFunction(this, NewPoolTString(name), rvalue, op, ext));
}
TPrecision TSymbolTable::getDefaultPrecision(TBasicType type) const
{
if (!SupportsPrecision(type))
......
......@@ -361,10 +361,14 @@ class TSymbolTable : angle::NonCopyable
return insert(level, constant);
}
bool insertConstIntExt(ESymbolLevel level, const char *ext, const char *name, int value)
bool insertConstIntExt(ESymbolLevel level,
const char *ext,
const char *name,
int value,
TPrecision precision)
{
TVariable *constant =
new TVariable(this, NewPoolTString(name), TType(EbtInt, EbpUndefined, EvqConst, 1));
new TVariable(this, NewPoolTString(name), TType(EbtInt, precision, EvqConst, 1));
TConstantUnion *unionArray = new TConstantUnion[1];
unionArray[0].setIConst(value);
constant->shareConstPointer(unionArray);
......@@ -451,6 +455,12 @@ class TSymbolTable : angle::NonCopyable
const TType *rvalue,
const char *name);
void insertBuiltInFunctionNoParametersExt(ESymbolLevel level,
const char *ext,
TOperator op,
const TType *rvalue,
const char *name);
TSymbol *find(const TString &name,
int shaderVersion,
bool *builtIn = nullptr,
......
......@@ -131,10 +131,12 @@ class CollectFragmentVariablesTest : public CollectVariablesTest
CollectFragmentVariablesTest() : CollectVariablesTest(GL_FRAGMENT_SHADER) {}
};
class CollectGeometryVariablesTest : public CollectVariablesTest
class CollectVariablesOESGeometryShaderTest : public CollectVariablesTest
{
public:
CollectGeometryVariablesTest() : CollectVariablesTest(GL_GEOMETRY_SHADER_OES) {}
CollectVariablesOESGeometryShaderTest(sh::GLenum shaderType) : CollectVariablesTest(shaderType)
{
}
protected:
void SetUp() override
......@@ -152,7 +154,16 @@ class CollectGeometryVariablesTest : public CollectVariablesTest
new TranslatorGLSL(mShaderType, SH_GLES3_1_SPEC, SH_GLSL_COMPATIBILITY_OUTPUT));
ASSERT_TRUE(mTranslator->Init(resources));
}
};
class CollectGeometryVariablesTest : public CollectVariablesOESGeometryShaderTest
{
public:
CollectGeometryVariablesTest() : CollectVariablesOESGeometryShaderTest(GL_GEOMETRY_SHADER_OES)
{
}
protected:
void compileGeometryShaderWithInputPrimitive(const std::string &inputPrimitive)
{
std::ostringstream sstream;
......@@ -168,6 +179,15 @@ class CollectGeometryVariablesTest : public CollectVariablesTest
}
};
class CollectFragmentVariablesOESGeometryShaderTest : public CollectVariablesOESGeometryShaderTest
{
public:
CollectFragmentVariablesOESGeometryShaderTest()
: CollectVariablesOESGeometryShaderTest(GL_FRAGMENT_SHADER)
{
}
};
TEST_F(CollectFragmentVariablesTest, SimpleOutputVar)
{
const std::string &shaderString =
......@@ -927,3 +947,243 @@ TEST_F(CollectGeometryVariablesTest, GLInArraySize)
EXPECT_EQ(kArraySizeForInputPrimitives[i], inBlock->arraySize);
}
}
// Test collecting gl_PrimitiveIDIn in a geometry shader.
TEST_F(CollectGeometryVariablesTest, CollectPrimitiveIDIn)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points) in;\n"
"layout (points, max_vertices = 2) out;\n"
"void main()\n"
"{\n"
" int value = gl_PrimitiveIDIn;\n"
"}\n";
compile(shaderString);
ASSERT_TRUE(mTranslator->getOutputVaryings().empty());
ASSERT_TRUE(mTranslator->getInBlocks().empty());
const auto &inputVaryings = mTranslator->getInputVaryings();
ASSERT_EQ(1u, inputVaryings.size());
const Varying *varying = &inputVaryings[0];
EXPECT_EQ("gl_PrimitiveIDIn", varying->name);
EXPECT_FALSE(varying->isArray());
EXPECT_FALSE(varying->isStruct());
EXPECT_TRUE(varying->staticUse);
EXPECT_TRUE(varying->isBuiltIn());
EXPECT_GLENUM_EQ(GL_HIGH_INT, varying->precision);
EXPECT_GLENUM_EQ(GL_INT, varying->type);
}
// Test collecting gl_InvocationID in a geometry shader.
TEST_F(CollectGeometryVariablesTest, CollectInvocationID)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points, invocations = 2) in;\n"
"layout (points, max_vertices = 2) out;\n"
"void main()\n"
"{\n"
" int value = gl_InvocationID;\n"
"}\n";
compile(shaderString);
ASSERT_TRUE(mTranslator->getOutputVaryings().empty());
ASSERT_TRUE(mTranslator->getInBlocks().empty());
const auto &inputVaryings = mTranslator->getInputVaryings();
ASSERT_EQ(1u, inputVaryings.size());
const Varying *varying = &inputVaryings[0];
EXPECT_EQ("gl_InvocationID", varying->name);
EXPECT_FALSE(varying->isArray());
EXPECT_FALSE(varying->isStruct());
EXPECT_TRUE(varying->staticUse);
EXPECT_TRUE(varying->isBuiltIn());
EXPECT_GLENUM_EQ(GL_HIGH_INT, varying->precision);
EXPECT_GLENUM_EQ(GL_INT, varying->type);
}
// Test collecting gl_in in a geometry shader when gl_in is indexed by an expression.
TEST_F(CollectGeometryVariablesTest, CollectGLInIndexedByExpression)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (triangles, invocations = 2) in;\n"
"layout (points, max_vertices = 2) out;\n"
"void main()\n"
"{\n"
" vec4 value = gl_in[gl_InvocationID + 1].gl_Position;\n"
"}\n";
compile(shaderString);
ASSERT_TRUE(mTranslator->getOutputVaryings().empty());
const auto &inBlocks = mTranslator->getInBlocks();
ASSERT_EQ(1u, inBlocks.size());
const InterfaceBlock *inBlock = &inBlocks[0];
EXPECT_EQ("gl_PerVertex", inBlock->name);
EXPECT_EQ("gl_in", inBlock->instanceName);
const auto &inputVaryings = mTranslator->getInputVaryings();
ASSERT_EQ(1u, inputVaryings.size());
const Varying *glInvocationID = &inputVaryings[0];
EXPECT_EQ("gl_InvocationID", glInvocationID->name);
}
// Test collecting gl_Position in a geometry shader.
TEST_F(CollectGeometryVariablesTest, CollectPosition)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points) in;\n"
"layout (points, max_vertices = 2) out;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(0.1, 0.2, 0.3, 1);\n"
"}\n";
compile(shaderString);
ASSERT_TRUE(mTranslator->getInputVaryings().empty());
ASSERT_TRUE(mTranslator->getInBlocks().empty());
const auto &outputVaryings = mTranslator->getOutputVaryings();
ASSERT_EQ(1u, outputVaryings.size());
const Varying *varying = &outputVaryings[0];
EXPECT_EQ("gl_Position", varying->name);
EXPECT_FALSE(varying->isArray());
EXPECT_FALSE(varying->isStruct());
EXPECT_TRUE(varying->staticUse);
EXPECT_TRUE(varying->isBuiltIn());
EXPECT_GLENUM_EQ(GL_HIGH_FLOAT, varying->precision);
EXPECT_GLENUM_EQ(GL_FLOAT_VEC4, varying->type);
}
// Test collecting gl_PrimitiveID in a geometry shader.
TEST_F(CollectGeometryVariablesTest, CollectPrimitiveID)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points) in;\n"
"layout (points, max_vertices = 2) out;\n"
"void main()\n"
"{\n"
" gl_PrimitiveID = 100;\n"
"}\n";
compile(shaderString);
ASSERT_TRUE(mTranslator->getInputVaryings().empty());
ASSERT_TRUE(mTranslator->getInBlocks().empty());
const auto &OutputVaryings = mTranslator->getOutputVaryings();
ASSERT_EQ(1u, OutputVaryings.size());
const Varying *varying = &OutputVaryings[0];
EXPECT_EQ("gl_PrimitiveID", varying->name);
EXPECT_FALSE(varying->isArray());
EXPECT_FALSE(varying->isStruct());
EXPECT_TRUE(varying->staticUse);
EXPECT_TRUE(varying->isBuiltIn());
EXPECT_GLENUM_EQ(GL_HIGH_INT, varying->precision);
EXPECT_GLENUM_EQ(GL_INT, varying->type);
}
// Test collecting gl_Layer in a geometry shader.
TEST_F(CollectGeometryVariablesTest, CollectLayer)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points) in;\n"
"layout (points, max_vertices = 2) out;\n"
"void main()\n"
"{\n"
" gl_Layer = 2;\n"
"}\n";
compile(shaderString);
ASSERT_TRUE(mTranslator->getInputVaryings().empty());
ASSERT_TRUE(mTranslator->getInBlocks().empty());
const auto &OutputVaryings = mTranslator->getOutputVaryings();
ASSERT_EQ(1u, OutputVaryings.size());
const Varying *varying = &OutputVaryings[0];
EXPECT_EQ("gl_Layer", varying->name);
EXPECT_FALSE(varying->isArray());
EXPECT_FALSE(varying->isStruct());
EXPECT_TRUE(varying->staticUse);
EXPECT_TRUE(varying->isBuiltIn());
EXPECT_GLENUM_EQ(GL_HIGH_INT, varying->precision);
EXPECT_GLENUM_EQ(GL_INT, varying->type);
}
// Test collecting gl_PrimitiveID in a fragment shader.
TEST_F(CollectFragmentVariablesOESGeometryShaderTest, CollectPrimitiveID)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"void main()\n"
"{\n"
" int value = gl_PrimitiveID;\n"
"}\n";
compile(shaderString);
ASSERT_TRUE(mTranslator->getOutputVaryings().empty());
const auto &inputVaryings = mTranslator->getInputVaryings();
ASSERT_EQ(1u, inputVaryings.size());
const Varying *varying = &inputVaryings[0];
EXPECT_EQ("gl_PrimitiveID", varying->name);
EXPECT_FALSE(varying->isArray());
EXPECT_FALSE(varying->isStruct());
EXPECT_TRUE(varying->staticUse);
EXPECT_TRUE(varying->isBuiltIn());
EXPECT_GLENUM_EQ(GL_HIGH_INT, varying->precision);
EXPECT_GLENUM_EQ(GL_INT, varying->type);
}
// Test collecting gl_Layer in a fragment shader.
TEST_F(CollectFragmentVariablesOESGeometryShaderTest, CollectLayer)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"void main()\n"
"{\n"
" int value = gl_Layer;\n"
"}\n";
compile(shaderString);
ASSERT_TRUE(mTranslator->getOutputVaryings().empty());
const auto &inputVaryings = mTranslator->getInputVaryings();
ASSERT_EQ(1u, inputVaryings.size());
const Varying *varying = &inputVaryings[0];
EXPECT_EQ("gl_Layer", varying->name);
EXPECT_FALSE(varying->isArray());
EXPECT_FALSE(varying->isStruct());
EXPECT_TRUE(varying->staticUse);
EXPECT_TRUE(varying->isBuiltIn());
EXPECT_GLENUM_EQ(GL_HIGH_INT, varying->precision);
EXPECT_GLENUM_EQ(GL_INT, varying->type);
}
......@@ -986,3 +986,173 @@ TEST_F(GeometryShaderTest, AssignValueToGLIn)
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Verify Geometry Shader supports all required built-in variables.
TEST_F(GeometryShaderTest, BuiltInVariables)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points, invocations = 2) in;\n"
"layout (points, max_vertices = 2) out;\n"
"void main()\n"
"{\n"
" gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
" int invocation = gl_InvocationID;\n"
" gl_Layer = invocation;\n"
" int primitiveIn = gl_PrimitiveIDIn;\n"
" gl_PrimitiveID = primitiveIn;\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Verify that gl_PrimitiveIDIn cannot be l-value.
TEST_F(GeometryShaderTest, AssignValueToGLPrimitiveIn)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points, invocations = 2) in;\n"
"layout (points, max_vertices = 2) out;\n"
"void main()\n"
"{\n"
" gl_PrimitiveIDIn = 1;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Verify that gl_InvocationID cannot be l-value.
TEST_F(GeometryShaderTest, AssignValueToGLInvocations)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points, invocations = 2) in;\n"
"layout (points, max_vertices = 2) out;\n"
"void main()\n"
"{\n"
" gl_InvocationID = 1;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Verify that both EmitVertex() and EndPrimitive() are supported in Geometry Shader.
TEST_F(GeometryShaderTest, GeometryShaderBuiltInFunctions)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points) in;\n"
"layout (points, max_vertices = 2) out;\n"
"void main()\n"
"{\n"
" gl_Position = gl_in[0].gl_Position;\n"
" EmitVertex();\n"
" EndPrimitive();\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Verify that using EmitVertex() or EndPrimitive() without GL_OES_geometry_shader declared causes a
// compile error.
TEST_F(GeometryShaderTest, GeometryShaderBuiltInFunctionsWithoutExtension)
{
const std::string &shaderString1 =
"#version 310 es\n"
"void main()\n"
"{\n"
" EmitVertex();\n"
"}\n";
const std::string &shaderString2 =
"#version 310 es\n"
"void main()\n"
"{\n"
" EndPrimitive();\n"
"}\n";
if (compile(shaderString1) || compile(shaderString2))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Verify that all required built-in constant values are supported in Geometry Shaders
TEST_F(GeometryShaderTest, GeometryShaderBuiltInConstants)
{
const std::string &kShaderHeader =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"layout (points) in;\n"
"layout (points, max_vertices = 2) out;\n"
"void main()\n"
"{\n"
" int val = ";
const std::array<std::string, 9> kGeometryShaderBuiltinConstants = {{
"gl_MaxGeometryInputComponents", "gl_MaxGeometryOutputComponents",
"gl_MaxGeometryImageUniforms", "gl_MaxGeometryTextureImageUnits",
"gl_MaxGeometryOutputVertices", "gl_MaxGeometryTotalOutputComponents",
"gl_MaxGeometryUniformComponents", "gl_MaxGeometryAtomicCounters",
"gl_MaxGeometryAtomicCounterBuffers",
}};
const std::string &kShaderTail =
";\n"
"}\n";
for (const std::string &kGSBuiltinConstant : kGeometryShaderBuiltinConstants)
{
std::ostringstream ostream;
ostream << kShaderHeader << kGSBuiltinConstant << kShaderTail;
if (!compile(ostream.str()))
{
FAIL() << "Shader compilation failed, expecting success: \n" << mInfoLog;
}
}
}
// Verify that using any Geometry Shader built-in constant values without GL_OES_geometry_shader
// declared causes a compile error.
TEST_F(GeometryShaderTest, GeometryShaderBuiltInConstantsWithoutExtension)
{
const std::string &kShaderHeader =
"#version 310 es\n"
"void main()\n"
"{\n"
" int val = ";
const std::array<std::string, 9> kGeometryShaderBuiltinConstants = {{
"gl_MaxGeometryInputComponents", "gl_MaxGeometryOutputComponents",
"gl_MaxGeometryImageUniforms", "gl_MaxGeometryTextureImageUnits",
"gl_MaxGeometryOutputVertices", "gl_MaxGeometryTotalOutputComponents",
"gl_MaxGeometryUniformComponents", "gl_MaxGeometryAtomicCounters",
"gl_MaxGeometryAtomicCounterBuffers",
}};
const std::string &kShaderTail =
";\n"
"}\n";
for (const std::string &kGSBuiltinConstant : kGeometryShaderBuiltinConstants)
{
std::ostringstream ostream;
ostream << kShaderHeader << kGSBuiltinConstant << kShaderTail;
if (compile(ostream.str()))
{
FAIL() << "Shader compilation succeeded, expecting failure: \n" << mInfoLog;
}
}
}
......@@ -107,6 +107,18 @@ class GeometryShaderValidationTest : public ShaderCompileTreeTest
ShShaderSpec getShaderSpec() const override { return SH_GLES3_1_SPEC; }
};
class FragmentShaderOESGeometryShaderValidationTest : public FragmentShaderValidationTest
{
public:
FragmentShaderOESGeometryShaderValidationTest() {}
protected:
void initResources(ShBuiltInResources *resources) override
{
resources->OES_geometry_shader = 1;
}
};
// 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)
......@@ -4418,3 +4430,199 @@ TEST_F(VertexShaderValidationTest, ViewportIndexInESSL310)
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that gl_PrimitiveID is valid in fragment shader with 'GL_OES_geometry_shader' declared.
TEST_F(FragmentShaderOESGeometryShaderValidationTest, PrimitiveIDWithExtension)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"precision mediump float;\n"
"layout(location = 0) out mediump vec4 fragColor;\n"
"void main(void)\n"
"{\n"
" vec4 data = vec4(0.1, 0.2, 0.3, 0.4);\n"
" float value = data[gl_PrimitiveID % 4];\n"
" fragColor = vec4(value, 0, 0, 1);\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Test that gl_PrimitiveID is invalid in fragment shader without 'GL_OES_geometry_shader' declared.
TEST_F(FragmentShaderOESGeometryShaderValidationTest, PrimitiveIDWithoutExtension)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(location = 0) out mediump vec4 fragColor;\n"
"void main(void)\n"
"{\n"
" vec4 data = vec4(0.1, 0.2, 0.3, 0.4);\n"
" float value = data[gl_PrimitiveID % 4];\n"
" fragColor = vec4(value, 0, 0, 1);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that gl_PrimitiveID cannot be l-value in fragment shader.
TEST_F(FragmentShaderOESGeometryShaderValidationTest, AssignValueToPrimitiveID)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"precision mediump float;\n"
"layout(location = 0) out mediump vec4 fragColor;\n"
"void main(void)\n"
"{\n"
" gl_PrimitiveID = 1;\n"
" fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that gl_Layer is valid in fragment shader with 'GL_OES_geometry_shader' declared.
TEST_F(FragmentShaderOESGeometryShaderValidationTest, LayerWithExtension)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"precision mediump float;\n"
"layout(location = 0) out mediump vec4 fragColor;\n"
"void main(void)\n"
"{\n"
" vec4 data = vec4(0.1, 0.2, 0.3, 0.4);\n"
" float value = data[gl_Layer % 4];\n"
" fragColor = vec4(value, 0, 0, 1);\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Test that gl_Layer is invalid in fragment shader without 'GL_OES_geometry_shader' declared.
TEST_F(FragmentShaderOESGeometryShaderValidationTest, LayerWithoutExtension)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(location = 0) out mediump vec4 fragColor;\n"
"void main(void)\n"
"{\n"
" vec4 data = vec4(0.1, 0.2, 0.3, 0.4);\n"
" float value = data[gl_Layer % 4];\n"
" fragColor = vec4(value, 0, 0, 1);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that gl_Layer cannot be l-value in fragment shader.
TEST_F(FragmentShaderOESGeometryShaderValidationTest, AssignValueToLayer)
{
const std::string &shaderString =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"precision mediump float;\n"
"layout(location = 0) out mediump vec4 fragColor;\n"
"void main(void)\n"
"{\n"
" gl_Layer = 1;\n"
" fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that all built-in constants defined in GL_OES_geometry_shader can be used in fragment shader
// with 'GL_OES_geometry_shader' declared.
TEST_F(FragmentShaderOESGeometryShaderValidationTest, GeometryShaderBuiltInConstants)
{
const std::string &kShaderHeader =
"#version 310 es\n"
"#extension GL_OES_geometry_shader : require\n"
"precision mediump float;\n"
"layout(location = 0) out mediump vec4 fragColor;\n"
"void main(void)\n"
"{\n"
" int val = ";
const std::array<std::string, 9> kGeometryShaderBuiltinConstants = {{
"gl_MaxGeometryInputComponents", "gl_MaxGeometryOutputComponents",
"gl_MaxGeometryImageUniforms", "gl_MaxGeometryTextureImageUnits",
"gl_MaxGeometryOutputVertices", "gl_MaxGeometryTotalOutputComponents",
"gl_MaxGeometryUniformComponents", "gl_MaxGeometryAtomicCounters",
"gl_MaxGeometryAtomicCounterBuffers",
}};
const std::string &kShaderTail =
";\n"
" fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
"}\n";
for (const std::string &kGSBuiltinConstant : kGeometryShaderBuiltinConstants)
{
std::ostringstream ostream;
ostream << kShaderHeader << kGSBuiltinConstant << kShaderTail;
if (!compile(ostream.str()))
{
FAIL() << "Shader compilation failed, expecting success: \n" << mInfoLog;
}
}
}
// Test that any built-in constants defined in GL_OES_geometry_shader cannot be used in fragment
// shader without 'GL_OES_geometry_shader' declared.
TEST_F(FragmentShaderOESGeometryShaderValidationTest,
GeometryShaderBuiltInConstantsWithoutExtension)
{
const std::string &kShaderHeader =
"#version 310 es\n"
"precision mediump float;\n"
"layout(location = 0) out mediump vec4 fragColor;\n"
"void main(void)\n"
"{\n"
" int val = ";
const std::array<std::string, 9> kGeometryShaderBuiltinConstants = {{
"gl_MaxGeometryInputComponents", "gl_MaxGeometryOutputComponents",
"gl_MaxGeometryImageUniforms", "gl_MaxGeometryTextureImageUnits",
"gl_MaxGeometryOutputVertices", "gl_MaxGeometryTotalOutputComponents",
"gl_MaxGeometryUniformComponents", "gl_MaxGeometryAtomicCounters",
"gl_MaxGeometryAtomicCounterBuffers",
}};
const std::string &kShaderTail =
";\n"
" fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
"}\n";
for (const std::string &kGSBuiltinConstant : kGeometryShaderBuiltinConstants)
{
std::ostringstream ostream;
ostream << kShaderHeader << kGSBuiltinConstant << kShaderTail;
if (compile(ostream.str()))
{
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