ES31: Implement Geometry Shader resource queries on OpenGL
This patch intends to implement all geometry shader related
resource queries on OpenGL back-ends.
This patch also fixes a memory leak by releasing the geometry
shader compiler handle in the destructor of the Compiler.
BUG=angleproject:1941, angleproject:2261
TEST=angle_end2end_tests
Change-Id: Ieb69c162d2fc6c6550e145d1ec7948c3d36d4d15
Reviewed-on: https://chromium-review.googlesource.com/784552
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/libANGLE/Caps.cpp b/src/libANGLE/Caps.cpp
index 44da2bb..4a66a02 100644
--- a/src/libANGLE/Caps.cpp
+++ b/src/libANGLE/Caps.cpp
@@ -228,9 +228,7 @@
robustResourceInitialization(false),
programCacheControl(false),
textureRectangle(false),
- geometryShader(false),
- maxGeometryOutputVertices(0),
- maxGeometryShaderInvocations(0)
+ geometryShader(false)
{
}
@@ -849,7 +847,28 @@
maxTransformFeedbackSeparateComponents(0),
// Table 20.49
- maxSamples(0)
+ maxSamples(0),
+
+ // Table 20.40 (cont.) (GL_EXT_geometry_shader)
+ maxFramebufferLayers(0),
+ layerProvokingVertex(0),
+
+ // Table 20.43gs (GL_EXT_geometry_shader)
+ maxGeometryUniformComponents(0),
+ maxGeometryUniformBlocks(0),
+ maxGeometryInputComponents(0),
+ maxGeometryOutputComponents(0),
+ maxGeometryOutputVertices(0),
+ maxGeometryTotalOutputComponents(0),
+ maxGeometryTextureImageUnits(0),
+ maxGeometryAtomicCounterBuffers(0),
+ maxGeometryAtomicCounters(0),
+ maxGeometryShaderStorageBlocks(0),
+ maxGeometryShaderInvocations(0),
+
+ // Table 20.46 (GL_EXT_geometry_shader)
+ maxGeometryImageUniforms(0),
+ maxCombinedGeometryUniformComponents(0)
{
for (size_t i = 0; i < 3; ++i)
{
@@ -1053,6 +1072,37 @@
caps.maxRectangleTextureSize = 64;
}
+ if (extensions.geometryShader)
+ {
+ // Table 20.40 (GL_EXT_geometry_shader)
+ caps.maxFramebufferLayers = 256;
+ caps.layerProvokingVertex = GL_LAST_VERTEX_CONVENTION_EXT;
+
+ // Table 20.43gs (GL_EXT_geometry_shader)
+ caps.maxGeometryUniformComponents = 1024;
+ caps.maxGeometryUniformBlocks = 12;
+ caps.maxGeometryInputComponents = 64;
+ caps.maxGeometryOutputComponents = 64;
+ caps.maxGeometryOutputVertices = 256;
+ caps.maxGeometryTotalOutputComponents = 1024;
+ caps.maxGeometryTextureImageUnits = 16;
+ caps.maxGeometryAtomicCounterBuffers = 0;
+ caps.maxGeometryAtomicCounters = 0;
+ caps.maxGeometryShaderStorageBlocks = 0;
+ caps.maxGeometryShaderInvocations = 32;
+
+ // Table 20.46 (GL_EXT_geometry_shader)
+ caps.maxGeometryImageUniforms = 0;
+ caps.maxCombinedGeometryUniformComponents =
+ caps.maxGeometryUniformBlocks * static_cast<GLuint>(caps.maxUniformBlockSize / 4) +
+ caps.maxGeometryUniformComponents;
+
+ // Table 20.46 (GL_EXT_geometry_shader)
+ caps.maxUniformBufferBindings = 48;
+ caps.maxCombinedUniformBlocks = 36;
+ caps.maxCombinedTextureImageUnits = 64;
+ }
+
return caps;
}
}
diff --git a/src/libANGLE/Caps.h b/src/libANGLE/Caps.h
index 64bdf97..a8453a5 100644
--- a/src/libANGLE/Caps.h
+++ b/src/libANGLE/Caps.h
@@ -373,11 +373,6 @@
// GL_EXT_geometry_shader
bool geometryShader;
- // GL_EXT_geometry_shader (May 31, 2016) Table 20.43gs: Implementation dependent geometry shader
- // limits
- // TODO(jiawei.shao@intel.com): add all implementation dependent geometry shader limits.
- GLuint maxGeometryOutputVertices;
- GLuint maxGeometryShaderInvocations;
};
struct ExtensionInfo
@@ -562,6 +557,29 @@
// ES 3.1 (April 29, 2015) Table 20.49: Framebuffer Dependent Values
GLuint maxSamples;
+
+ // GL_EXT_geometry_shader (May 31, 2016) Table 20.40: Implementation-Dependent Values (cont.)
+ GLuint maxFramebufferLayers;
+ GLuint layerProvokingVertex;
+
+ // GL_EXT_geometry_shader (May 31, 2016) Table 20.43gs: Implementation dependent geometry shader
+ // limits
+ GLuint maxGeometryUniformComponents;
+ GLuint maxGeometryUniformBlocks;
+ GLuint maxGeometryInputComponents;
+ GLuint maxGeometryOutputComponents;
+ GLuint maxGeometryOutputVertices;
+ GLuint maxGeometryTotalOutputComponents;
+ GLuint maxGeometryTextureImageUnits;
+ GLuint maxGeometryAtomicCounterBuffers;
+ GLuint maxGeometryAtomicCounters;
+ GLuint maxGeometryShaderStorageBlocks;
+ GLuint maxGeometryShaderInvocations;
+
+ // GL_EXT_geometry_shader (May 31, 2016) Table 20.46: Implementation dependent aggregate shader
+ // limits
+ GLuint maxGeometryImageUniforms;
+ GLuint maxCombinedGeometryUniformComponents;
};
Caps GenerateMinimumCaps(const Version &clientVersion, const Extensions &extensions);
diff --git a/src/libANGLE/Compiler.cpp b/src/libANGLE/Compiler.cpp
index 236c7e1..b524520 100644
--- a/src/libANGLE/Compiler.cpp
+++ b/src/libANGLE/Compiler.cpp
@@ -132,10 +132,20 @@
}
// Geometry Shader constants
+ // TODO(jiawei.shao@intel.com): use EXT_geometry_shader everywhere in compiler.
mResources.OES_geometry_shader = extensions.geometryShader;
- // TODO(jiawei.shao@intel.com): initialize all implementation dependent geometry shader limits.
- mResources.MaxGeometryOutputVertices = extensions.maxGeometryOutputVertices;
- mResources.MaxGeometryShaderInvocations = extensions.maxGeometryShaderInvocations;
+ mResources.MaxGeometryUniformComponents = caps.maxGeometryUniformComponents;
+ mResources.MaxGeometryUniformBlocks = caps.maxGeometryUniformBlocks;
+ mResources.MaxGeometryInputComponents = caps.maxGeometryInputComponents;
+ mResources.MaxGeometryOutputComponents = caps.maxGeometryOutputComponents;
+ mResources.MaxGeometryOutputVertices = caps.maxGeometryOutputVertices;
+ mResources.MaxGeometryTotalOutputComponents = caps.maxGeometryTotalOutputComponents;
+ mResources.MaxGeometryTextureImageUnits = caps.maxGeometryTextureImageUnits;
+ mResources.MaxGeometryAtomicCounterBuffers = caps.maxGeometryAtomicCounterBuffers;
+ mResources.MaxGeometryAtomicCounters = caps.maxGeometryAtomicCounters;
+ mResources.MaxGeometryShaderStorageBlocks = caps.maxGeometryShaderStorageBlocks;
+ mResources.MaxGeometryShaderInvocations = caps.maxGeometryShaderInvocations;
+ mResources.MaxGeometryImageUniforms = caps.maxGeometryImageUniforms;
}
Compiler::~Compiler()
@@ -167,6 +177,15 @@
activeCompilerHandles--;
}
+ if (mGeometryCompiler)
+ {
+ sh::Destruct(mGeometryCompiler);
+ mGeometryCompiler = nullptr;
+
+ ASSERT(activeCompilerHandles > 0);
+ activeCompilerHandles--;
+ }
+
if (activeCompilerHandles == 0)
{
sh::Finalize();
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index f638bed..caebc20 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -1508,6 +1508,53 @@
case GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT:
*params = mCaps.shaderStorageBufferOffsetAlignment;
break;
+
+ // GL_EXT_geometry_shader
+ case GL_MAX_FRAMEBUFFER_LAYERS_EXT:
+ *params = mCaps.maxFramebufferLayers;
+ break;
+ case GL_LAYER_PROVOKING_VERTEX_EXT:
+ *params = mCaps.layerProvokingVertex;
+ break;
+ case GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT:
+ *params = mCaps.maxGeometryUniformComponents;
+ break;
+ case GL_MAX_GEOMETRY_UNIFORM_BLOCKS_EXT:
+ *params = mCaps.maxGeometryUniformBlocks;
+ break;
+ case GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS_EXT:
+ *params = mCaps.maxCombinedGeometryUniformComponents;
+ break;
+ case GL_MAX_GEOMETRY_INPUT_COMPONENTS_EXT:
+ *params = mCaps.maxGeometryInputComponents;
+ break;
+ case GL_MAX_GEOMETRY_OUTPUT_COMPONENTS_EXT:
+ *params = mCaps.maxGeometryOutputComponents;
+ break;
+ case GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT:
+ *params = mCaps.maxGeometryOutputVertices;
+ break;
+ case GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT:
+ *params = mCaps.maxGeometryTotalOutputComponents;
+ break;
+ case GL_MAX_GEOMETRY_SHADER_INVOCATIONS_EXT:
+ *params = mCaps.maxGeometryShaderInvocations;
+ break;
+ case GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT:
+ *params = mCaps.maxGeometryTextureImageUnits;
+ break;
+ case GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT:
+ *params = mCaps.maxGeometryAtomicCounterBuffers;
+ break;
+ case GL_MAX_GEOMETRY_ATOMIC_COUNTERS_EXT:
+ *params = mCaps.maxGeometryAtomicCounters;
+ break;
+ case GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT:
+ *params = mCaps.maxGeometryImageUniforms;
+ break;
+ case GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT:
+ *params = mCaps.maxGeometryShaderStorageBlocks;
+ break;
default:
mGLState.getIntegerv(this, pname, params);
break;
diff --git a/src/libANGLE/ContextState.cpp b/src/libANGLE/ContextState.cpp
index d109cca..5321ab2 100644
--- a/src/libANGLE/ContextState.cpp
+++ b/src/libANGLE/ContextState.cpp
@@ -721,6 +721,31 @@
return true;
}
+ if (getExtensions().geometryShader)
+ {
+ switch (pname)
+ {
+ case GL_MAX_FRAMEBUFFER_LAYERS_EXT:
+ case GL_LAYER_PROVOKING_VERTEX_EXT:
+ case GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT:
+ case GL_MAX_GEOMETRY_UNIFORM_BLOCKS_EXT:
+ case GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS_EXT:
+ case GL_MAX_GEOMETRY_INPUT_COMPONENTS_EXT:
+ case GL_MAX_GEOMETRY_OUTPUT_COMPONENTS_EXT:
+ case GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT:
+ case GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT:
+ case GL_MAX_GEOMETRY_SHADER_INVOCATIONS_EXT:
+ case GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT:
+ case GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT:
+ case GL_MAX_GEOMETRY_ATOMIC_COUNTERS_EXT:
+ case GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT:
+ case GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT:
+ *type = GL_INT;
+ *numParams = 1;
+ return true;
+ }
+ }
+
return false;
}
diff --git a/src/libANGLE/renderer/gl/renderergl_utils.cpp b/src/libANGLE/renderer/gl/renderergl_utils.cpp
index 7b7a680..7878eea 100644
--- a/src/libANGLE/renderer/gl/renderergl_utils.cpp
+++ b/src/libANGLE/renderer/gl/renderergl_utils.cpp
@@ -1017,20 +1017,69 @@
QuerySingleGLInt(functions, GL_MAX_RECTANGLE_TEXTURE_SIZE_ANGLE);
}
- // We need at least OpenGL 4.3 to support all features and constants defined in
+ // OpenGL 4.3 (and above) can support all features and constants defined in
// GL_EXT_geometry_shader.
if (functions->isAtLeastGL(gl::Version(4, 3)) || functions->isAtLeastGLES(gl::Version(3, 2)) ||
functions->hasGLESExtension("GL_OES_geometry_shader") ||
- functions->hasGLESExtension("GL_EXT_geometry_shader"))
+ functions->hasGLESExtension("GL_EXT_geometry_shader") ||
+ // OpenGL 4.0 adds the support for instanced geometry shader
+ // GL_ARB_shader_atomic_counters adds atomic counters to geometry shader
+ // GL_ARB_shader_storage_buffer_object adds shader storage buffers to geometry shader
+ // GL_ARB_shader_image_load_store adds images to geometry shader
+ (functions->isAtLeastGL(gl::Version(4, 0)) &&
+ functions->hasGLExtension("GL_ARB_shader_atomic_counters") &&
+ functions->hasGLExtension("GL_ARB_shader_storage_buffer_object") &&
+ functions->hasGLExtension("GL_ARB_shader_image_load_store")))
{
extensions->geometryShader = true;
- // TODO(jiawei.shao@intel.com): initialize all implementation dependent geometry shader
- // limits.
- extensions->maxGeometryOutputVertices =
+ caps->maxFramebufferLayers = QuerySingleGLInt(functions, GL_MAX_FRAMEBUFFER_LAYERS_EXT);
+
+ // GL_PROVOKING_VERTEX isn't a valid return value of GL_LAYER_PROVOKING_VERTEX_EXT in
+ // GL_EXT_geometry_shader SPEC, however it is legal in desktop OpenGL, which means the value
+ // follows the one set by glProvokingVertex.
+ // [OpenGL 4.3] Chapter 11.3.4.6
+ // The vertex conventions followed for gl_Layer and gl_ViewportIndex may be determined by
+ // calling GetIntegerv with the symbolic constants LAYER_PROVOKING_VERTEX and
+ // VIEWPORT_INDEX_PROVOKING_VERTEX, respectively. For either query, if the value returned is
+ // PROVOKING_VERTEX, then vertex selection follows the convention specified by
+ // ProvokingVertex.
+ caps->layerProvokingVertex = QuerySingleGLInt(functions, GL_LAYER_PROVOKING_VERTEX_EXT);
+ if (caps->layerProvokingVertex == GL_PROVOKING_VERTEX)
+ {
+ // We should use GL_LAST_VERTEX_CONVENTION_EXT instead because desktop OpenGL SPEC
+ // requires the initial value of provoking vertex mode is LAST_VERTEX_CONVENTION.
+ // [OpenGL 4.3] Chapter 13.4
+ // The initial value of the provoking vertex mode is LAST_VERTEX_CONVENTION.
+ caps->layerProvokingVertex = GL_LAST_VERTEX_CONVENTION_EXT;
+ }
+
+ caps->maxGeometryUniformComponents =
+ QuerySingleGLInt(functions, GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT);
+ caps->maxGeometryUniformBlocks =
+ QuerySingleGLInt(functions, GL_MAX_GEOMETRY_UNIFORM_BLOCKS_EXT);
+ caps->maxCombinedGeometryUniformComponents =
+ QuerySingleGLInt(functions, GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS_EXT);
+ caps->maxGeometryInputComponents =
+ QuerySingleGLInt(functions, GL_MAX_GEOMETRY_INPUT_COMPONENTS_EXT);
+ caps->maxGeometryOutputComponents =
+ QuerySingleGLInt(functions, GL_MAX_GEOMETRY_OUTPUT_COMPONENTS_EXT);
+ caps->maxGeometryOutputVertices =
QuerySingleGLInt(functions, GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT);
- extensions->maxGeometryShaderInvocations =
+ caps->maxGeometryTotalOutputComponents =
+ QuerySingleGLInt(functions, GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT);
+ caps->maxGeometryShaderInvocations =
QuerySingleGLInt(functions, GL_MAX_GEOMETRY_SHADER_INVOCATIONS_EXT);
+ caps->maxGeometryTextureImageUnits =
+ QuerySingleGLInt(functions, GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT);
+ caps->maxGeometryAtomicCounterBuffers =
+ QuerySingleGLInt(functions, GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT);
+ caps->maxGeometryAtomicCounters =
+ QuerySingleGLInt(functions, GL_MAX_GEOMETRY_ATOMIC_COUNTERS_EXT);
+ caps->maxGeometryImageUniforms =
+ QuerySingleGLInt(functions, GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT);
+ caps->maxGeometryShaderStorageBlocks =
+ QuerySingleGLInt(functions, GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT);
}
}
diff --git a/src/libANGLE/renderer/null/ContextNULL.cpp b/src/libANGLE/renderer/null/ContextNULL.cpp
index a8da191..818eb82 100644
--- a/src/libANGLE/renderer/null/ContextNULL.cpp
+++ b/src/libANGLE/renderer/null/ContextNULL.cpp
@@ -87,6 +87,7 @@
mExtensions.textureCompressionASTCLDR = true;
mExtensions.compressedETC1RGB8Texture = true;
mExtensions.lossyETCDecode = true;
+ mExtensions.geometryShader = true;
const gl::Version maxClientVersion(3, 1);
mCaps = GenerateMinimumCaps(maxClientVersion, mExtensions);
diff --git a/src/tests/gl_tests/GeometryShaderTest.cpp b/src/tests/gl_tests/GeometryShaderTest.cpp
index 62bf205..bf55d06 100644
--- a/src/tests/gl_tests/GeometryShaderTest.cpp
+++ b/src/tests/gl_tests/GeometryShaderTest.cpp
@@ -69,6 +69,64 @@
EXPECT_GL_NO_ERROR();
}
+// Verify that all the implementation dependent geometry shader related resource limits meet the
+// requirement of GL_EXT_geometry_shader SPEC.
+TEST_P(GeometryShaderTest, GeometryShaderImplementationDependentLimits)
+{
+ ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_EXT_geometry_shader"));
+
+ const std::map<GLenum, int> limits = {{GL_MAX_FRAMEBUFFER_LAYERS_EXT, 256},
+ {GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT, 1024},
+ {GL_MAX_GEOMETRY_UNIFORM_BLOCKS_EXT, 12},
+ {GL_MAX_GEOMETRY_INPUT_COMPONENTS_EXT, 64},
+ {GL_MAX_GEOMETRY_OUTPUT_COMPONENTS_EXT, 64},
+ {GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT, 256},
+ {GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT, 1024},
+ {GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT, 16},
+ {GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT, 0},
+ {GL_MAX_GEOMETRY_ATOMIC_COUNTERS_EXT, 0},
+ {GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT, 0},
+ {GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT, 0},
+ {GL_MAX_GEOMETRY_SHADER_INVOCATIONS_EXT, 32}};
+
+ GLint value;
+ for (const auto &limit : limits)
+ {
+ value = 0;
+ glGetIntegerv(limit.first, &value);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_GE(value, limit.second);
+ }
+
+ value = 0;
+ glGetIntegerv(GL_LAYER_PROVOKING_VERTEX_EXT, &value);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_TRUE(value == GL_FIRST_VERTEX_CONVENTION_EXT || value == GL_LAST_VERTEX_CONVENTION_EXT ||
+ value == GL_UNDEFINED_VERTEX_EXT);
+}
+
+// Verify that all the combined resource limits meet the requirement of GL_EXT_geometry_shader SPEC.
+TEST_P(GeometryShaderTest, CombinedResourceLimits)
+{
+ ANGLE_SKIP_TEST_IF(!extensionEnabled("GL_EXT_geometry_shader"));
+
+ // See http://anglebug.com/2261.
+ ANGLE_SKIP_TEST_IF(IsAndroid());
+
+ const std::map<GLenum, int> limits = {{GL_MAX_UNIFORM_BUFFER_BINDINGS, 48},
+ {GL_MAX_COMBINED_UNIFORM_BLOCKS, 36},
+ {GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, 64}};
+
+ GLint value;
+ for (const auto &limit : limits)
+ {
+ value = 0;
+ glGetIntegerv(limit.first, &value);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_GE(value, limit.second);
+ }
+}
+
ANGLE_INSTANTIATE_TEST(GeometryShaderTestES3, ES3_OPENGL(), ES3_OPENGLES(), ES3_D3D11());
ANGLE_INSTANTIATE_TEST(GeometryShaderTest, ES31_OPENGL(), ES31_OPENGLES(), ES31_D3D11());
}