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 @@
// Version number for shader translation API.
// It is incremented every time the API changes.
#define ANGLE_SH_VERSION 195
#define ANGLE_SH_VERSION 196
enum ShShaderSpec
{
......@@ -602,6 +602,9 @@ bool GetUniformBlockRegister(const ShHandle handle,
// 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);
bool HasValidGeometryShaderInputPrimitiveType(const ShHandle handle);
bool HasValidGeometryShaderOutputPrimitiveType(const ShHandle handle);
bool HasValidGeometryShaderMaxVertices(const ShHandle handle);
GLenum GetGeometryShaderInputPrimitiveType(const ShHandle handle);
GLenum GetGeometryShaderOutputPrimitiveType(const ShHandle handle);
int GetGeometryShaderInvocations(const ShHandle handle);
......
......@@ -133,8 +133,6 @@ GLenum GetGeometryShaderPrimitiveTypeEnum(sh::TLayoutPrimitiveType primitiveType
return GL_TRIANGLE_STRIP;
case EptUndefined:
return GL_INVALID_VALUE;
default:
UNREACHABLE();
return GL_INVALID_VALUE;
......@@ -531,6 +529,39 @@ const std::map<std::string, unsigned int> *GetUniformRegisterMap(const ShHandle
#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)
{
ASSERT(handle);
......@@ -572,7 +603,9 @@ int GetGeometryShaderMaxVertices(const ShHandle handle)
TCompiler *compiler = base->getAsCompiler();
ASSERT(compiler);
return compiler->getGeometryShaderMaxVertices();
int maxVertices = compiler->getGeometryShaderMaxVertices();
ASSERT(maxVertices >= 0);
return maxVertices;
}
} // namespace sh
......@@ -230,6 +230,11 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context,
state->mComputeShaderLocalSize[1] = 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>();
static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
......@@ -451,6 +456,12 @@ void MemoryProgramCache::Serialize(const Context *context,
stream.writeInt(computeLocalSize[1]);
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);
static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
......@@ -604,10 +615,11 @@ void MemoryProgramCache::ComputeHash(const Context *context,
const Shader *vertexShader = program->getAttachedVertexShader();
const Shader *fragmentShader = program->getAttachedFragmentShader();
const Shader *computeShader = program->getAttachedComputeShader();
const Shader *geometryShader = program->getAttachedGeometryShader();
// Compute the program hash. Start with the shader hashes and resource strings.
HashStream hashStream;
hashStream << vertexShader << fragmentShader << computeShader;
hashStream << vertexShader << fragmentShader << computeShader << geometryShader;
// Add some ANGLE metadata and Context properties, such as version and back-end.
hashStream << ANGLE_COMMIT_HASH << context->getClientMajorVersion()
......
......@@ -587,7 +587,12 @@ ProgramState::ProgramState()
mImageUniformRange(0, 0),
mAtomicCounterUniformRange(0, 0),
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);
}
......@@ -1070,6 +1075,11 @@ void Program::updateLinkedShaderStages()
{
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
......@@ -1095,6 +1105,10 @@ void Program::unlink()
mState.mSamplerBindings.clear();
mState.mImageBindings.clear();
mState.mNumViews = -1;
mState.mGeometryShaderInputPrimitiveType = GL_TRIANGLES;
mState.mGeometryShaderOutputPrimitiveType = GL_TRIANGLE_STRIP;
mState.mGeometryShaderInvocations = 1;
mState.mGeometryShaderMaxVertices = 0;
mValidated = false;
......@@ -2067,9 +2081,11 @@ bool Program::linkValidateShaders(const Context *context, InfoLog &infoLog)
Shader *vertexShader = mState.mAttachedVertexShader;
Shader *fragmentShader = mState.mAttachedFragmentShader;
Shader *computeShader = mState.mAttachedComputeShader;
Shader *geometryShader = mState.mAttachedGeometryShader;
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.
// If there are of both types attached, then linking should fail.
// OpenGL ES 3.10, 7.3 Program Objects, under LinkProgram
......@@ -2114,11 +2130,67 @@ bool Program::linkValidateShaders(const Context *context, InfoLog &infoLog)
}
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.";
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;
......
......@@ -426,6 +426,12 @@ class ProgramState final : angle::NonCopyable
// ANGLE_multiview.
int mNumViews;
// GL_EXT_geometry_shader.
GLenum mGeometryShaderInputPrimitiveType;
GLenum mGeometryShaderOutputPrimitiveType;
int mGeometryShaderInvocations;
int mGeometryShaderMaxVertices;
};
class ProgramBindings final : angle::NonCopyable
......@@ -495,6 +501,7 @@ class Program final : angle::NonCopyable, public LabeledObject
bool hasLinkedVertexShader() const { return mState.mLinkedShaderStages[SHADER_VERTEX]; }
bool hasLinkedFragmentShader() const { return mState.mLinkedShaderStages[SHADER_FRAGMENT]; }
bool hasLinkedComputeShader() const { return mState.mLinkedShaderStages[SHADER_COMPUTE]; }
bool hasLinkedGeometryShader() const { return mState.mLinkedShaderStages[SHADER_GEOMETRY]; }
Error loadBinary(const Context *context,
GLenum binaryFormat,
......
......@@ -101,10 +101,7 @@ ShaderState::ShaderState(GLenum shaderType)
mShaderType(shaderType),
mShaderVersion(100),
mNumViews(-1),
mGeometryShaderInputPrimitiveType(GL_INVALID_VALUE),
mGeometryShaderOutputPrimitiveType(GL_INVALID_VALUE),
mGeometryShaderInvocations(1),
mGeometryShaderMaxVertices(-1),
mCompileStatus(CompileStatus::NOT_COMPILED)
{
mLocalSize.fill(-1);
......@@ -302,10 +299,10 @@ void Shader::compile(const Context *context)
mState.mActiveAttributes.clear();
mState.mActiveOutputVariables.clear();
mState.mNumViews = -1;
mState.mGeometryShaderInputPrimitiveType = GL_INVALID_VALUE;
mState.mGeometryShaderOutputPrimitiveType = GL_INVALID_VALUE;
mState.mGeometryShaderInvocations = 1;
mState.mGeometryShaderMaxVertices = -1;
mState.mGeometryShaderInputPrimitiveType.reset();
mState.mGeometryShaderOutputPrimitiveType.reset();
mState.mGeometryShaderMaxVertices.reset();
mState.mGeometryShaderInvocations = 1;
mState.mCompileStatus = CompileStatus::COMPILE_REQUESTED;
mBoundCompiler.set(context, context->getCompiler());
......@@ -426,12 +423,22 @@ void Shader::resolveCompile(const Context *context)
mState.mInputVaryings = GetShaderVariables(sh::GetInputVaryings(compilerHandle));
mState.mOutputVaryings = GetShaderVariables(sh::GetOutputVaryings(compilerHandle));
mState.mGeometryShaderInputPrimitiveType =
sh::GetGeometryShaderInputPrimitiveType(compilerHandle);
mState.mGeometryShaderOutputPrimitiveType =
sh::GetGeometryShaderOutputPrimitiveType(compilerHandle);
if (sh::HasValidGeometryShaderInputPrimitiveType(compilerHandle))
{
mState.mGeometryShaderInputPrimitiveType =
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.mGeometryShaderMaxVertices = sh::GetGeometryShaderMaxVertices(compilerHandle);
break;
}
default:
......@@ -580,6 +587,30 @@ int Shader::getNumViews(const Context *context)
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
{
ASSERT(mBoundCompiler.get());
......
......@@ -102,10 +102,10 @@ class ShaderState final : angle::NonCopyable
int mNumViews;
// Geometry Shader.
GLenum mGeometryShaderInputPrimitiveType;
GLenum mGeometryShaderOutputPrimitiveType;
Optional<GLenum> mGeometryShaderInputPrimitiveType;
Optional<GLenum> mGeometryShaderOutputPrimitiveType;
Optional<GLint> mGeometryShaderMaxVertices;
int mGeometryShaderInvocations;
int mGeometryShaderMaxVertices;
// Indicates if this shader has been successfully compiled
CompileStatus mCompileStatus;
......@@ -177,6 +177,11 @@ class Shader final : angle::NonCopyable, public LabeledObject
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;
private:
......
......@@ -178,10 +178,16 @@ gl::LinkResult ProgramGL::link(const gl::Context *context,
const ShaderGL *vertexShaderGL = GetImplAs<ShaderGL>(mState.getAttachedVertexShader());
const ShaderGL *fragmentShaderGL = GetImplAs<ShaderGL>(mState.getAttachedFragmentShader());
const ShaderGL *geometryShaderGL =
rx::SafeGetImplAs<ShaderGL, gl::Shader>(mState.getAttachedGeometryShader());
// Attach the shaders
mFunctions->attachShader(mProgramID, vertexShaderGL->getShaderID());
mFunctions->attachShader(mProgramID, fragmentShaderGL->getShaderID());
if (geometryShaderGL)
{
mFunctions->attachShader(mProgramID, geometryShaderGL->getShaderID());
}
// Bind attribute locations to match the GL layer.
for (const sh::Attribute &attribute : mState.getAttributes())
......@@ -201,6 +207,10 @@ gl::LinkResult ProgramGL::link(const gl::Context *context,
// Detach the shaders
mFunctions->detachShader(mProgramID, vertexShaderGL->getShaderID());
mFunctions->detachShader(mProgramID, fragmentShaderGL->getShaderID());
if (geometryShaderGL)
{
mFunctions->detachShader(mProgramID, geometryShaderGL->getShaderID());
}
}
// Verify the link
......
......@@ -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.global_invocation_id = 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
1665 WIN NVIDIA OPENGL : dEQP-GLES31.functional.draw_indirect.negative.command_offset_not_in_buffer_unsigned32_wrap = FAIL
......@@ -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_highp_geometry = 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.debug.negative_coverage.callbacks.shader_directive.geometry_shader = FAIL
1941 OPENGL D3D11 : dEQP-GLES31.functional.debug.negative_coverage.log.shader_directive.geometry_shader = FAIL
......@@ -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.draw_* = 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.log.compute.program_not_active = FAIL
......
......@@ -15,6 +15,52 @@ namespace
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
......@@ -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(GeometryShaderTest, ES31_OPENGL(), ES31_OPENGLES(), ES31_D3D11());
}
......@@ -122,6 +122,17 @@ GLuint CompileProgramWithTransformFeedback(
const std::vector<std::string> &transformFeedbackVaryings,
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 vs = CompileShader(GL_VERTEX_SHADER, vsSource);
......@@ -141,6 +152,21 @@ GLuint CompileProgramWithTransformFeedback(
glAttachShader(program, 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)
{
std::vector<const char *> constCharTFVaryings;
......@@ -161,8 +187,16 @@ GLuint CompileProgramWithTransformFeedback(
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;
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)
......
......@@ -26,7 +26,16 @@ CompileProgramWithTransformFeedback(const std::string &vsSource,
const std::string &fsSource,
const std::vector<std::string> &transformFeedbackVaryings,
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 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 CompileComputeProgram(const std::string &csSource,
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