Commit 4ed05da2 by Jiawei Shao Committed by Commit Bot

ES31: Add link validation on geometry shader itself

This patch intends to support program link validation on geometry shader itself. A link error should occur when linking a program with a geometry shader that lacks input primitive or output primitive or the declaration of 'max_vertices'. This patch also adds the support of linking a program with geometry shader in angle_end2end_tests. BUG=angleproject:1941 TEST=angle_end2end_tests dEQP-GLES31.functional.shaders.linkage.es31.geometry.varying.rules.unspecified_* Change-Id: I25fb08514753102f5dd3ab86211c05d2ca4fd185 Reviewed-on: https://chromium-review.googlesource.com/898842 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 30414789
...@@ -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 195 #define ANGLE_SH_VERSION 196
enum ShShaderSpec enum ShShaderSpec
{ {
...@@ -602,6 +602,9 @@ bool GetUniformBlockRegister(const ShHandle handle, ...@@ -602,6 +602,9 @@ bool GetUniformBlockRegister(const ShHandle handle,
// Note that the map contains also registers of samplers that have been extracted from structs. // Note that the map contains also registers of samplers that have been extracted from structs.
const std::map<std::string, unsigned int> *GetUniformRegisterMap(const ShHandle handle); const std::map<std::string, unsigned int> *GetUniformRegisterMap(const ShHandle handle);
bool HasValidGeometryShaderInputPrimitiveType(const ShHandle handle);
bool HasValidGeometryShaderOutputPrimitiveType(const ShHandle handle);
bool HasValidGeometryShaderMaxVertices(const ShHandle handle);
GLenum GetGeometryShaderInputPrimitiveType(const ShHandle handle); GLenum GetGeometryShaderInputPrimitiveType(const ShHandle handle);
GLenum GetGeometryShaderOutputPrimitiveType(const ShHandle handle); GLenum GetGeometryShaderOutputPrimitiveType(const ShHandle handle);
int GetGeometryShaderInvocations(const ShHandle handle); int GetGeometryShaderInvocations(const ShHandle handle);
......
...@@ -133,8 +133,6 @@ GLenum GetGeometryShaderPrimitiveTypeEnum(sh::TLayoutPrimitiveType primitiveType ...@@ -133,8 +133,6 @@ GLenum GetGeometryShaderPrimitiveTypeEnum(sh::TLayoutPrimitiveType primitiveType
return GL_TRIANGLE_STRIP; return GL_TRIANGLE_STRIP;
case EptUndefined: case EptUndefined:
return GL_INVALID_VALUE;
default: default:
UNREACHABLE(); UNREACHABLE();
return GL_INVALID_VALUE; return GL_INVALID_VALUE;
...@@ -531,6 +529,39 @@ const std::map<std::string, unsigned int> *GetUniformRegisterMap(const ShHandle ...@@ -531,6 +529,39 @@ const std::map<std::string, unsigned int> *GetUniformRegisterMap(const ShHandle
#endif // ANGLE_ENABLE_HLSL #endif // ANGLE_ENABLE_HLSL
} }
bool HasValidGeometryShaderInputPrimitiveType(const ShHandle handle)
{
ASSERT(handle);
TShHandleBase *base = static_cast<TShHandleBase *>(handle);
TCompiler *compiler = base->getAsCompiler();
ASSERT(compiler);
return compiler->getGeometryShaderInputPrimitiveType() != EptUndefined;
}
bool HasValidGeometryShaderOutputPrimitiveType(const ShHandle handle)
{
ASSERT(handle);
TShHandleBase *base = static_cast<TShHandleBase *>(handle);
TCompiler *compiler = base->getAsCompiler();
ASSERT(compiler);
return compiler->getGeometryShaderOutputPrimitiveType() != EptUndefined;
}
bool HasValidGeometryShaderMaxVertices(const ShHandle handle)
{
ASSERT(handle);
TShHandleBase *base = static_cast<TShHandleBase *>(handle);
TCompiler *compiler = base->getAsCompiler();
ASSERT(compiler);
return compiler->getGeometryShaderMaxVertices() >= 0;
}
GLenum GetGeometryShaderInputPrimitiveType(const ShHandle handle) GLenum GetGeometryShaderInputPrimitiveType(const ShHandle handle)
{ {
ASSERT(handle); ASSERT(handle);
...@@ -572,7 +603,9 @@ int GetGeometryShaderMaxVertices(const ShHandle handle) ...@@ -572,7 +603,9 @@ int GetGeometryShaderMaxVertices(const ShHandle handle)
TCompiler *compiler = base->getAsCompiler(); TCompiler *compiler = base->getAsCompiler();
ASSERT(compiler); ASSERT(compiler);
return compiler->getGeometryShaderMaxVertices(); int maxVertices = compiler->getGeometryShaderMaxVertices();
ASSERT(maxVertices >= 0);
return maxVertices;
} }
} // namespace sh } // namespace sh
...@@ -230,6 +230,11 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context, ...@@ -230,6 +230,11 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context,
state->mComputeShaderLocalSize[1] = stream.readInt<int>(); state->mComputeShaderLocalSize[1] = stream.readInt<int>();
state->mComputeShaderLocalSize[2] = stream.readInt<int>(); state->mComputeShaderLocalSize[2] = stream.readInt<int>();
state->mGeometryShaderInputPrimitiveType = stream.readInt<GLenum>();
state->mGeometryShaderOutputPrimitiveType = stream.readInt<GLenum>();
state->mGeometryShaderInvocations = stream.readInt<int>();
state->mGeometryShaderMaxVertices = stream.readInt<int>();
state->mNumViews = stream.readInt<int>(); state->mNumViews = stream.readInt<int>();
static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8, static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
...@@ -451,6 +456,12 @@ void MemoryProgramCache::Serialize(const Context *context, ...@@ -451,6 +456,12 @@ void MemoryProgramCache::Serialize(const Context *context,
stream.writeInt(computeLocalSize[1]); stream.writeInt(computeLocalSize[1]);
stream.writeInt(computeLocalSize[2]); stream.writeInt(computeLocalSize[2]);
ASSERT(state.mGeometryShaderInvocations >= 1 && state.mGeometryShaderMaxVertices >= 0);
stream.writeInt(state.mGeometryShaderInputPrimitiveType);
stream.writeInt(state.mGeometryShaderOutputPrimitiveType);
stream.writeInt(state.mGeometryShaderInvocations);
stream.writeInt(state.mGeometryShaderMaxVertices);
stream.writeInt(state.mNumViews); stream.writeInt(state.mNumViews);
static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8, static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
...@@ -604,10 +615,11 @@ void MemoryProgramCache::ComputeHash(const Context *context, ...@@ -604,10 +615,11 @@ void MemoryProgramCache::ComputeHash(const Context *context,
const Shader *vertexShader = program->getAttachedVertexShader(); const Shader *vertexShader = program->getAttachedVertexShader();
const Shader *fragmentShader = program->getAttachedFragmentShader(); const Shader *fragmentShader = program->getAttachedFragmentShader();
const Shader *computeShader = program->getAttachedComputeShader(); const Shader *computeShader = program->getAttachedComputeShader();
const Shader *geometryShader = program->getAttachedGeometryShader();
// Compute the program hash. Start with the shader hashes and resource strings. // Compute the program hash. Start with the shader hashes and resource strings.
HashStream hashStream; HashStream hashStream;
hashStream << vertexShader << fragmentShader << computeShader; hashStream << vertexShader << fragmentShader << computeShader << geometryShader;
// Add some ANGLE metadata and Context properties, such as version and back-end. // Add some ANGLE metadata and Context properties, such as version and back-end.
hashStream << ANGLE_COMMIT_HASH << context->getClientMajorVersion() hashStream << ANGLE_COMMIT_HASH << context->getClientMajorVersion()
......
...@@ -587,7 +587,12 @@ ProgramState::ProgramState() ...@@ -587,7 +587,12 @@ ProgramState::ProgramState()
mImageUniformRange(0, 0), mImageUniformRange(0, 0),
mAtomicCounterUniformRange(0, 0), mAtomicCounterUniformRange(0, 0),
mBinaryRetrieveableHint(false), mBinaryRetrieveableHint(false),
mNumViews(-1) mNumViews(-1),
// [GL_EXT_geometry_shader] Table 20.22
mGeometryShaderInputPrimitiveType(GL_TRIANGLES),
mGeometryShaderOutputPrimitiveType(GL_TRIANGLE_STRIP),
mGeometryShaderInvocations(1),
mGeometryShaderMaxVertices(0)
{ {
mComputeShaderLocalSize.fill(1); mComputeShaderLocalSize.fill(1);
} }
...@@ -1070,6 +1075,11 @@ void Program::updateLinkedShaderStages() ...@@ -1070,6 +1075,11 @@ void Program::updateLinkedShaderStages()
{ {
mState.mLinkedShaderStages.set(SHADER_COMPUTE); mState.mLinkedShaderStages.set(SHADER_COMPUTE);
} }
if (mState.mAttachedGeometryShader)
{
mState.mLinkedShaderStages.set(SHADER_GEOMETRY);
}
} }
// Returns the program object to an unlinked state, before re-linking, or at destruction // Returns the program object to an unlinked state, before re-linking, or at destruction
...@@ -1095,6 +1105,10 @@ void Program::unlink() ...@@ -1095,6 +1105,10 @@ void Program::unlink()
mState.mSamplerBindings.clear(); mState.mSamplerBindings.clear();
mState.mImageBindings.clear(); mState.mImageBindings.clear();
mState.mNumViews = -1; mState.mNumViews = -1;
mState.mGeometryShaderInputPrimitiveType = GL_TRIANGLES;
mState.mGeometryShaderOutputPrimitiveType = GL_TRIANGLE_STRIP;
mState.mGeometryShaderInvocations = 1;
mState.mGeometryShaderMaxVertices = 0;
mValidated = false; mValidated = false;
...@@ -2067,9 +2081,11 @@ bool Program::linkValidateShaders(const Context *context, InfoLog &infoLog) ...@@ -2067,9 +2081,11 @@ bool Program::linkValidateShaders(const Context *context, InfoLog &infoLog)
Shader *vertexShader = mState.mAttachedVertexShader; Shader *vertexShader = mState.mAttachedVertexShader;
Shader *fragmentShader = mState.mAttachedFragmentShader; Shader *fragmentShader = mState.mAttachedFragmentShader;
Shader *computeShader = mState.mAttachedComputeShader; Shader *computeShader = mState.mAttachedComputeShader;
Shader *geometryShader = mState.mAttachedGeometryShader;
bool isComputeShaderAttached = (computeShader != nullptr); bool isComputeShaderAttached = (computeShader != nullptr);
bool isGraphicsShaderAttached = (vertexShader != nullptr || fragmentShader != nullptr); bool isGraphicsShaderAttached =
(vertexShader != nullptr || fragmentShader != nullptr || geometryShader != nullptr);
// Check whether we both have a compute and non-compute shaders attached. // Check whether we both have a compute and non-compute shaders attached.
// If there are of both types attached, then linking should fail. // If there are of both types attached, then linking should fail.
// OpenGL ES 3.10, 7.3 Program Objects, under LinkProgram // OpenGL ES 3.10, 7.3 Program Objects, under LinkProgram
...@@ -2114,11 +2130,67 @@ bool Program::linkValidateShaders(const Context *context, InfoLog &infoLog) ...@@ -2114,11 +2130,67 @@ bool Program::linkValidateShaders(const Context *context, InfoLog &infoLog)
} }
ASSERT(vertexShader->getType() == GL_VERTEX_SHADER); ASSERT(vertexShader->getType() == GL_VERTEX_SHADER);
if (fragmentShader->getShaderVersion(context) != vertexShader->getShaderVersion(context)) int vertexShaderVersion = vertexShader->getShaderVersion(context);
if (fragmentShader->getShaderVersion(context) != vertexShaderVersion)
{ {
infoLog << "Fragment shader version does not match vertex shader version."; infoLog << "Fragment shader version does not match vertex shader version.";
return false; return false;
} }
if (geometryShader)
{
// [GL_EXT_geometry_shader] Chapter 7
// Linking can fail for a variety of reasons as specified in the OpenGL ES Shading
// Language Specification, as well as any of the following reasons:
// * One or more of the shader objects attached to <program> are not compiled
// successfully.
// * The shaders do not use the same shader language version.
// * <program> contains objects to form a geometry shader, and
// - <program> is not separable and contains no objects to form a vertex shader; or
// - the input primitive type, output primitive type, or maximum output vertex count
// is not specified in the compiled geometry shader object.
if (!geometryShader->isCompiled(context))
{
infoLog << "The attached geometry shader isn't compiled.";
return false;
}
if (geometryShader->getShaderVersion(context) != vertexShaderVersion)
{
mInfoLog << "Geometry shader version does not match vertex shader version.";
return false;
}
ASSERT(geometryShader->getType() == GL_GEOMETRY_SHADER_EXT);
Optional<GLenum> inputPrimitive =
geometryShader->getGeometryShaderInputPrimitiveType(context);
if (!inputPrimitive.valid())
{
mInfoLog << "Input primitive type is not specified in the geometry shader.";
return false;
}
Optional<GLenum> outputPrimitive =
geometryShader->getGeometryShaderOutputPrimitiveType(context);
if (!outputPrimitive.valid())
{
mInfoLog << "Output primitive type is not specified in the geometry shader.";
return false;
}
Optional<GLint> maxVertices = geometryShader->getGeometryShaderMaxVertices(context);
if (!maxVertices.valid())
{
mInfoLog << "'max_vertices' is not specified in the geometry shader.";
return false;
}
mState.mGeometryShaderInputPrimitiveType = inputPrimitive.value();
mState.mGeometryShaderOutputPrimitiveType = outputPrimitive.value();
mState.mGeometryShaderMaxVertices = maxVertices.value();
mState.mGeometryShaderInvocations =
geometryShader->getGeometryShaderInvocations(context);
}
} }
return true; return true;
......
...@@ -426,6 +426,12 @@ class ProgramState final : angle::NonCopyable ...@@ -426,6 +426,12 @@ class ProgramState final : angle::NonCopyable
// ANGLE_multiview. // ANGLE_multiview.
int mNumViews; int mNumViews;
// GL_EXT_geometry_shader.
GLenum mGeometryShaderInputPrimitiveType;
GLenum mGeometryShaderOutputPrimitiveType;
int mGeometryShaderInvocations;
int mGeometryShaderMaxVertices;
}; };
class ProgramBindings final : angle::NonCopyable class ProgramBindings final : angle::NonCopyable
...@@ -495,6 +501,7 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -495,6 +501,7 @@ class Program final : angle::NonCopyable, public LabeledObject
bool hasLinkedVertexShader() const { return mState.mLinkedShaderStages[SHADER_VERTEX]; } bool hasLinkedVertexShader() const { return mState.mLinkedShaderStages[SHADER_VERTEX]; }
bool hasLinkedFragmentShader() const { return mState.mLinkedShaderStages[SHADER_FRAGMENT]; } bool hasLinkedFragmentShader() const { return mState.mLinkedShaderStages[SHADER_FRAGMENT]; }
bool hasLinkedComputeShader() const { return mState.mLinkedShaderStages[SHADER_COMPUTE]; } bool hasLinkedComputeShader() const { return mState.mLinkedShaderStages[SHADER_COMPUTE]; }
bool hasLinkedGeometryShader() const { return mState.mLinkedShaderStages[SHADER_GEOMETRY]; }
Error loadBinary(const Context *context, Error loadBinary(const Context *context,
GLenum binaryFormat, GLenum binaryFormat,
......
...@@ -101,10 +101,7 @@ ShaderState::ShaderState(GLenum shaderType) ...@@ -101,10 +101,7 @@ ShaderState::ShaderState(GLenum shaderType)
mShaderType(shaderType), mShaderType(shaderType),
mShaderVersion(100), mShaderVersion(100),
mNumViews(-1), mNumViews(-1),
mGeometryShaderInputPrimitiveType(GL_INVALID_VALUE),
mGeometryShaderOutputPrimitiveType(GL_INVALID_VALUE),
mGeometryShaderInvocations(1), mGeometryShaderInvocations(1),
mGeometryShaderMaxVertices(-1),
mCompileStatus(CompileStatus::NOT_COMPILED) mCompileStatus(CompileStatus::NOT_COMPILED)
{ {
mLocalSize.fill(-1); mLocalSize.fill(-1);
...@@ -302,10 +299,10 @@ void Shader::compile(const Context *context) ...@@ -302,10 +299,10 @@ void Shader::compile(const Context *context)
mState.mActiveAttributes.clear(); mState.mActiveAttributes.clear();
mState.mActiveOutputVariables.clear(); mState.mActiveOutputVariables.clear();
mState.mNumViews = -1; mState.mNumViews = -1;
mState.mGeometryShaderInputPrimitiveType = GL_INVALID_VALUE; mState.mGeometryShaderInputPrimitiveType.reset();
mState.mGeometryShaderOutputPrimitiveType = GL_INVALID_VALUE; mState.mGeometryShaderOutputPrimitiveType.reset();
mState.mGeometryShaderInvocations = 1; mState.mGeometryShaderMaxVertices.reset();
mState.mGeometryShaderMaxVertices = -1; mState.mGeometryShaderInvocations = 1;
mState.mCompileStatus = CompileStatus::COMPILE_REQUESTED; mState.mCompileStatus = CompileStatus::COMPILE_REQUESTED;
mBoundCompiler.set(context, context->getCompiler()); mBoundCompiler.set(context, context->getCompiler());
...@@ -426,12 +423,22 @@ void Shader::resolveCompile(const Context *context) ...@@ -426,12 +423,22 @@ void Shader::resolveCompile(const Context *context)
mState.mInputVaryings = GetShaderVariables(sh::GetInputVaryings(compilerHandle)); mState.mInputVaryings = GetShaderVariables(sh::GetInputVaryings(compilerHandle));
mState.mOutputVaryings = GetShaderVariables(sh::GetOutputVaryings(compilerHandle)); mState.mOutputVaryings = GetShaderVariables(sh::GetOutputVaryings(compilerHandle));
mState.mGeometryShaderInputPrimitiveType = if (sh::HasValidGeometryShaderInputPrimitiveType(compilerHandle))
sh::GetGeometryShaderInputPrimitiveType(compilerHandle); {
mState.mGeometryShaderOutputPrimitiveType = mState.mGeometryShaderInputPrimitiveType =
sh::GetGeometryShaderOutputPrimitiveType(compilerHandle); sh::GetGeometryShaderInputPrimitiveType(compilerHandle);
}
if (sh::HasValidGeometryShaderOutputPrimitiveType(compilerHandle))
{
mState.mGeometryShaderOutputPrimitiveType =
sh::GetGeometryShaderOutputPrimitiveType(compilerHandle);
}
if (sh::HasValidGeometryShaderMaxVertices(compilerHandle))
{
mState.mGeometryShaderMaxVertices =
sh::GetGeometryShaderMaxVertices(compilerHandle);
}
mState.mGeometryShaderInvocations = sh::GetGeometryShaderInvocations(compilerHandle); mState.mGeometryShaderInvocations = sh::GetGeometryShaderInvocations(compilerHandle);
mState.mGeometryShaderMaxVertices = sh::GetGeometryShaderMaxVertices(compilerHandle);
break; break;
} }
default: default:
...@@ -580,6 +587,30 @@ int Shader::getNumViews(const Context *context) ...@@ -580,6 +587,30 @@ int Shader::getNumViews(const Context *context)
return mState.mNumViews; return mState.mNumViews;
} }
Optional<GLenum> Shader::getGeometryShaderInputPrimitiveType(const Context *context)
{
resolveCompile(context);
return mState.mGeometryShaderInputPrimitiveType;
}
Optional<GLenum> Shader::getGeometryShaderOutputPrimitiveType(const Context *context)
{
resolveCompile(context);
return mState.mGeometryShaderOutputPrimitiveType;
}
int Shader::getGeometryShaderInvocations(const Context *context)
{
resolveCompile(context);
return mState.mGeometryShaderInvocations;
}
Optional<GLint> Shader::getGeometryShaderMaxVertices(const Context *context)
{
resolveCompile(context);
return mState.mGeometryShaderMaxVertices;
}
const std::string &Shader::getCompilerResourcesString() const const std::string &Shader::getCompilerResourcesString() const
{ {
ASSERT(mBoundCompiler.get()); ASSERT(mBoundCompiler.get());
......
...@@ -102,10 +102,10 @@ class ShaderState final : angle::NonCopyable ...@@ -102,10 +102,10 @@ class ShaderState final : angle::NonCopyable
int mNumViews; int mNumViews;
// Geometry Shader. // Geometry Shader.
GLenum mGeometryShaderInputPrimitiveType; Optional<GLenum> mGeometryShaderInputPrimitiveType;
GLenum mGeometryShaderOutputPrimitiveType; Optional<GLenum> mGeometryShaderOutputPrimitiveType;
Optional<GLint> mGeometryShaderMaxVertices;
int mGeometryShaderInvocations; int mGeometryShaderInvocations;
int mGeometryShaderMaxVertices;
// Indicates if this shader has been successfully compiled // Indicates if this shader has been successfully compiled
CompileStatus mCompileStatus; CompileStatus mCompileStatus;
...@@ -177,6 +177,11 @@ class Shader final : angle::NonCopyable, public LabeledObject ...@@ -177,6 +177,11 @@ class Shader final : angle::NonCopyable, public LabeledObject
int getNumViews(const Context *context); int getNumViews(const Context *context);
Optional<GLenum> getGeometryShaderInputPrimitiveType(const Context *context);
Optional<GLenum> getGeometryShaderOutputPrimitiveType(const Context *context);
int getGeometryShaderInvocations(const Context *context);
Optional<GLint> getGeometryShaderMaxVertices(const Context *context);
const std::string &getCompilerResourcesString() const; const std::string &getCompilerResourcesString() const;
private: private:
......
...@@ -178,10 +178,16 @@ gl::LinkResult ProgramGL::link(const gl::Context *context, ...@@ -178,10 +178,16 @@ gl::LinkResult ProgramGL::link(const gl::Context *context,
const ShaderGL *vertexShaderGL = GetImplAs<ShaderGL>(mState.getAttachedVertexShader()); const ShaderGL *vertexShaderGL = GetImplAs<ShaderGL>(mState.getAttachedVertexShader());
const ShaderGL *fragmentShaderGL = GetImplAs<ShaderGL>(mState.getAttachedFragmentShader()); const ShaderGL *fragmentShaderGL = GetImplAs<ShaderGL>(mState.getAttachedFragmentShader());
const ShaderGL *geometryShaderGL =
rx::SafeGetImplAs<ShaderGL, gl::Shader>(mState.getAttachedGeometryShader());
// Attach the shaders // Attach the shaders
mFunctions->attachShader(mProgramID, vertexShaderGL->getShaderID()); mFunctions->attachShader(mProgramID, vertexShaderGL->getShaderID());
mFunctions->attachShader(mProgramID, fragmentShaderGL->getShaderID()); mFunctions->attachShader(mProgramID, fragmentShaderGL->getShaderID());
if (geometryShaderGL)
{
mFunctions->attachShader(mProgramID, geometryShaderGL->getShaderID());
}
// Bind attribute locations to match the GL layer. // Bind attribute locations to match the GL layer.
for (const sh::Attribute &attribute : mState.getAttributes()) for (const sh::Attribute &attribute : mState.getAttributes())
...@@ -201,6 +207,10 @@ gl::LinkResult ProgramGL::link(const gl::Context *context, ...@@ -201,6 +207,10 @@ gl::LinkResult ProgramGL::link(const gl::Context *context,
// Detach the shaders // Detach the shaders
mFunctions->detachShader(mProgramID, vertexShaderGL->getShaderID()); mFunctions->detachShader(mProgramID, vertexShaderGL->getShaderID());
mFunctions->detachShader(mProgramID, fragmentShaderGL->getShaderID()); mFunctions->detachShader(mProgramID, fragmentShaderGL->getShaderID());
if (geometryShaderGL)
{
mFunctions->detachShader(mProgramID, geometryShaderGL->getShaderID());
}
} }
// Verify the link // Verify the link
......
...@@ -1120,6 +1120,7 @@ ...@@ -1120,6 +1120,7 @@
1442 D3D11 : dEQP-GLES31.functional.shaders.builtin_var.compute.local_invocation_id = FAIL 1442 D3D11 : dEQP-GLES31.functional.shaders.builtin_var.compute.local_invocation_id = FAIL
1442 D3D11 : dEQP-GLES31.functional.shaders.builtin_var.compute.global_invocation_id = FAIL 1442 D3D11 : dEQP-GLES31.functional.shaders.builtin_var.compute.global_invocation_id = FAIL
1442 D3D11 : dEQP-GLES31.functional.shaders.builtin_var.compute.local_invocation_index = FAIL 1442 D3D11 : dEQP-GLES31.functional.shaders.builtin_var.compute.local_invocation_index = FAIL
1941 D3D11 : dEQP-GLES31.functional.shaders.linkage.es31.geometry.* = FAIL
// OPENGL Failing Tests // OPENGL Failing Tests
1665 WIN NVIDIA OPENGL : dEQP-GLES31.functional.draw_indirect.negative.command_offset_not_in_buffer_unsigned32_wrap = FAIL 1665 WIN NVIDIA OPENGL : dEQP-GLES31.functional.draw_indirect.negative.command_offset_not_in_buffer_unsigned32_wrap = FAIL
...@@ -1654,7 +1655,6 @@ ...@@ -1654,7 +1655,6 @@
1941 OPENGL D3D11 : dEQP-GLES31.functional.shaders.builtin_functions.integer.findmsb.uvec4_mediump_geometry = FAIL 1941 OPENGL D3D11 : dEQP-GLES31.functional.shaders.builtin_functions.integer.findmsb.uvec4_mediump_geometry = FAIL
1941 OPENGL D3D11 : dEQP-GLES31.functional.shaders.builtin_functions.integer.findmsb.uvec4_highp_geometry = FAIL 1941 OPENGL D3D11 : dEQP-GLES31.functional.shaders.builtin_functions.integer.findmsb.uvec4_highp_geometry = FAIL
1941 OPENGL D3D11 : dEQP-GLES31.functional.shaders.builtin_constants.geometry_shader.* = FAIL 1941 OPENGL D3D11 : dEQP-GLES31.functional.shaders.builtin_constants.geometry_shader.* = FAIL
1941 OPENGL D3D11 : dEQP-GLES31.functional.shaders.linkage.geometry.* = FAIL
1941 OPENGL D3D11 : dEQP-GLES31.functional.state_query.program.geometry_shader_state_get_programiv = FAIL 1941 OPENGL D3D11 : dEQP-GLES31.functional.state_query.program.geometry_shader_state_get_programiv = FAIL
1941 OPENGL D3D11 : dEQP-GLES31.functional.debug.negative_coverage.callbacks.shader_directive.geometry_shader = FAIL 1941 OPENGL D3D11 : dEQP-GLES31.functional.debug.negative_coverage.callbacks.shader_directive.geometry_shader = FAIL
1941 OPENGL D3D11 : dEQP-GLES31.functional.debug.negative_coverage.log.shader_directive.geometry_shader = FAIL 1941 OPENGL D3D11 : dEQP-GLES31.functional.debug.negative_coverage.log.shader_directive.geometry_shader = FAIL
...@@ -1669,7 +1669,11 @@ ...@@ -1669,7 +1669,11 @@
1941 OPENGL D3D11 : dEQP-GLES31.functional.geometry_shading.instanced.invocation_output_* = FAIL 1941 OPENGL D3D11 : dEQP-GLES31.functional.geometry_shading.instanced.invocation_output_* = FAIL
1941 OPENGL D3D11 : dEQP-GLES31.functional.geometry_shading.instanced.draw_* = FAIL 1941 OPENGL D3D11 : dEQP-GLES31.functional.geometry_shading.instanced.draw_* = FAIL
1941 OPENGL D3D11 : dEQP-GLES31.functional.geometry_shading.negative.* = FAIL 1941 OPENGL D3D11 : dEQP-GLES31.functional.geometry_shading.negative.* = FAIL
1941 OPENGL D3D11 : dEQP-GLES31.functional.shaders.linkage.es31.geometry.* = FAIL 1941 OPENGL D3D11 : dEQP-GLES31.functional.shaders.linkage.es31.geometry.varying.rules.input_* = FAIL
1941 OPENGL D3D11 : dEQP-GLES31.functional.shaders.linkage.es31.geometry.varying.rules.output_* = FAIL
1941 OPENGL D3D11 : dEQP-GLES31.functional.shaders.linkage.es31.geometry.varying.types.* = FAIL
1941 OPENGL D3D11 : dEQP-GLES31.functional.shaders.linkage.es31.geometry.varying.qualifiers.* = FAIL
1941 OPENGL D3D11 : dEQP-GLES31.functional.shaders.linkage.es31.geometry.uniform.* = FAIL
2324 DEBUG RELEASE : dEQP-GLES31.functional.debug.negative_coverage.callbacks.compute.program_not_active = FAIL 2324 DEBUG RELEASE : dEQP-GLES31.functional.debug.negative_coverage.callbacks.compute.program_not_active = FAIL
2324 DEBUG RELEASE : dEQP-GLES31.functional.debug.negative_coverage.log.compute.program_not_active = FAIL 2324 DEBUG RELEASE : dEQP-GLES31.functional.debug.negative_coverage.log.compute.program_not_active = FAIL
......
...@@ -15,6 +15,52 @@ namespace ...@@ -15,6 +15,52 @@ namespace
class GeometryShaderTest : public ANGLETest class GeometryShaderTest : public ANGLETest
{ {
protected:
static std::string CreateEmptyGeometryShader(const std::string &inputPrimitive,
const std::string &outputPrimitive,
int invocations,
int maxVertices)
{
std::ostringstream ostream;
ostream << "#version 310 es\n"
"#extension GL_EXT_geometry_shader : require\n";
if (!inputPrimitive.empty())
{
ostream << "layout (" << inputPrimitive << ") in;\n";
}
if (!outputPrimitive.empty())
{
ostream << "layout (" << outputPrimitive << ") out;\n";
}
if (invocations > 0)
{
ostream << "layout (invocations = " << invocations << ") in;\n";
}
if (maxVertices >= 0)
{
ostream << "layout (max_vertices = " << maxVertices << ") out;\n";
}
ostream << "void main()\n"
"{\n"
"}";
return ostream.str();
}
const std::string kDefaultVertexShader =
R"(#version 310 es
void main()
{
gl_Position = vec4(1.0, 0.0, 0.0, 1.0);
})";
const std::string kDefaultFragmentShader =
R"(#version 310 es
precision mediump float;
layout (location = 0) out vec4 frag_out;
void main()
{
frag_out = vec4(1.0, 0.0, 0.0, 1.0);
})";
}; };
class GeometryShaderTestES3 : public ANGLETest class GeometryShaderTestES3 : public ANGLETest
...@@ -127,6 +173,101 @@ TEST_P(GeometryShaderTest, CombinedResourceLimits) ...@@ -127,6 +173,101 @@ TEST_P(GeometryShaderTest, CombinedResourceLimits)
} }
} }
// Verify that linking a program with an uncompiled geometry shader causes a link failure.
TEST_P(GeometryShaderTest, LinkWithUncompiledGeoemtryShader)
{
ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_EXT_geometry_shader"));
GLuint vertexShader = CompileShader(GL_VERTEX_SHADER, kDefaultVertexShader);
GLuint fragmentShader = CompileShader(GL_FRAGMENT_SHADER, kDefaultFragmentShader);
ASSERT_NE(0u, vertexShader);
ASSERT_NE(0u, fragmentShader);
GLuint geometryShader = glCreateShader(GL_GEOMETRY_SHADER_EXT);
GLuint program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glAttachShader(program, geometryShader);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
glDeleteShader(geometryShader);
glLinkProgram(program);
GLint linkStatus;
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
EXPECT_EQ(0, linkStatus);
glDeleteProgram(program);
ASSERT_GL_NO_ERROR();
}
// Verify that linking a program with geometry shader whose version is different from other shaders
// in this program causes a link error.
TEST_P(GeometryShaderTest, LinkWhenShaderVersionMismatch)
{
ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_EXT_geometry_shader"));
const std::string &kDefaultVertexShaderVersion300 =
R"(#version 300 es
void main()
{
gl_Position = vec4(1.0, 0.0, 0.0, 1.0);
})";
const std::string kDefaultFragmentShaderVersion300 =
R"(#version 300 es
precision mediump float;
layout (location = 0) out vec4 frag_out;
void main()
{
frag_out = vec4(1.0, 0.0, 0.0, 1.0);
})";
const std::string &emptyGeometryShader = CreateEmptyGeometryShader("points", "points", 2, 1);
GLuint program = CompileProgramWithGS(kDefaultVertexShaderVersion300, emptyGeometryShader,
kDefaultFragmentShaderVersion300);
EXPECT_EQ(0u, program);
}
// Verify that linking a program with geometry shader that lacks input primitive,
// output primitive, or declaration on 'max_vertices' causes a link failure.
TEST_P(GeometryShaderTest, LinkValidationOnGeometryShaderLayouts)
{
ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_EXT_geometry_shader"));
const std::string &gsWithoutInputPrimitive = CreateEmptyGeometryShader("", "points", 2, 1);
const std::string &gsWithoutOutputPrimitive = CreateEmptyGeometryShader("points", "", 2, 1);
const std::string &gsWithoutInvocations = CreateEmptyGeometryShader("points", "points", -1, 1);
const std::string &gsWithoutMaxVertices = CreateEmptyGeometryShader("points", "points", 2, -1);
// Linking a program with a geometry shader that only lacks 'invocations' should not cause a
// link failure.
GLuint program =
CompileProgramWithGS(kDefaultVertexShader, gsWithoutInvocations, kDefaultFragmentShader);
EXPECT_NE(0u, program);
glDeleteProgram(program);
// Linking a program with a geometry shader that lacks input primitive, output primitive or
// 'max_vertices' causes a link failure.
program =
CompileProgramWithGS(kDefaultVertexShader, gsWithoutInputPrimitive, kDefaultFragmentShader);
EXPECT_EQ(0u, program);
program = CompileProgramWithGS(kDefaultVertexShader, gsWithoutOutputPrimitive,
kDefaultFragmentShader);
EXPECT_EQ(0u, program);
program =
CompileProgramWithGS(kDefaultVertexShader, gsWithoutMaxVertices, kDefaultFragmentShader);
EXPECT_EQ(0u, program);
ASSERT_GL_NO_ERROR();
}
ANGLE_INSTANTIATE_TEST(GeometryShaderTestES3, ES3_OPENGL(), ES3_OPENGLES(), ES3_D3D11()); ANGLE_INSTANTIATE_TEST(GeometryShaderTestES3, ES3_OPENGL(), ES3_OPENGLES(), ES3_D3D11());
ANGLE_INSTANTIATE_TEST(GeometryShaderTest, ES31_OPENGL(), ES31_OPENGLES(), ES31_D3D11()); ANGLE_INSTANTIATE_TEST(GeometryShaderTest, ES31_OPENGL(), ES31_OPENGLES(), ES31_D3D11());
} }
...@@ -122,6 +122,17 @@ GLuint CompileProgramWithTransformFeedback( ...@@ -122,6 +122,17 @@ GLuint CompileProgramWithTransformFeedback(
const std::vector<std::string> &transformFeedbackVaryings, const std::vector<std::string> &transformFeedbackVaryings,
GLenum bufferMode) GLenum bufferMode)
{ {
return CompileProgramWithGSAndTransformFeedback(vsSource, "", fsSource,
transformFeedbackVaryings, bufferMode);
}
GLuint CompileProgramWithGSAndTransformFeedback(
const std::string &vsSource,
const std::string &gsSource,
const std::string &fsSource,
const std::vector<std::string> &transformFeedbackVaryings,
GLenum bufferMode)
{
GLuint program = glCreateProgram(); GLuint program = glCreateProgram();
GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource); GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
...@@ -141,6 +152,21 @@ GLuint CompileProgramWithTransformFeedback( ...@@ -141,6 +152,21 @@ GLuint CompileProgramWithTransformFeedback(
glAttachShader(program, fs); glAttachShader(program, fs);
glDeleteShader(fs); glDeleteShader(fs);
if (!gsSource.empty())
{
GLuint gs = CompileShader(GL_GEOMETRY_SHADER_EXT, gsSource);
if (gs == 0)
{
glDeleteShader(vs);
glDeleteShader(fs);
glDeleteProgram(program);
return 0;
}
glAttachShader(program, gs);
glDeleteShader(gs);
}
if (transformFeedbackVaryings.size() > 0) if (transformFeedbackVaryings.size() > 0)
{ {
std::vector<const char *> constCharTFVaryings; std::vector<const char *> constCharTFVaryings;
...@@ -161,8 +187,16 @@ GLuint CompileProgramWithTransformFeedback( ...@@ -161,8 +187,16 @@ GLuint CompileProgramWithTransformFeedback(
GLuint CompileProgram(const std::string &vsSource, const std::string &fsSource) GLuint CompileProgram(const std::string &vsSource, const std::string &fsSource)
{ {
return CompileProgramWithGS(vsSource, "", fsSource);
}
GLuint CompileProgramWithGS(const std::string &vsSource,
const std::string &gsSource,
const std::string &fsSource)
{
std::vector<std::string> emptyVector; std::vector<std::string> emptyVector;
return CompileProgramWithTransformFeedback(vsSource, fsSource, emptyVector, GL_NONE); return CompileProgramWithGSAndTransformFeedback(vsSource, gsSource, fsSource, emptyVector,
GL_NONE);
} }
GLuint CompileProgramFromFiles(const std::string &vsPath, const std::string &fsPath) GLuint CompileProgramFromFiles(const std::string &vsPath, const std::string &fsPath)
......
...@@ -26,7 +26,16 @@ CompileProgramWithTransformFeedback(const std::string &vsSource, ...@@ -26,7 +26,16 @@ CompileProgramWithTransformFeedback(const std::string &vsSource,
const std::string &fsSource, const std::string &fsSource,
const std::vector<std::string> &transformFeedbackVaryings, const std::vector<std::string> &transformFeedbackVaryings,
GLenum bufferMode); GLenum bufferMode);
ANGLE_EXPORT GLuint
CompileProgramWithGSAndTransformFeedback(const std::string &vsSource,
const std::string &gsSource,
const std::string &fsSource,
const std::vector<std::string> &transformFeedbackVaryings,
GLenum bufferMode);
ANGLE_EXPORT GLuint CompileProgram(const std::string &vsSource, const std::string &fsSource); ANGLE_EXPORT GLuint CompileProgram(const std::string &vsSource, const std::string &fsSource);
ANGLE_EXPORT GLuint CompileProgramWithGS(const std::string &vsSource,
const std::string &gsSource,
const std::string &fsSource);
ANGLE_EXPORT GLuint CompileProgramFromFiles(const std::string &vsPath, const std::string &fsPath); ANGLE_EXPORT GLuint CompileProgramFromFiles(const std::string &vsPath, const std::string &fsPath);
ANGLE_EXPORT GLuint CompileComputeProgram(const std::string &csSource, ANGLE_EXPORT GLuint CompileComputeProgram(const std::string &csSource,
bool outputErrorMessages = true); bool outputErrorMessages = true);
......
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