GL_EXT_geometry_shader#

Supported Hardware#

Series6XT

Valid APIs#

OpenGL ES 3.1

Description#

Geometry Shaders are a new programmable pipeline step that sits in the current OpenGL ES pipeline directly after primitive assembly, and before clipping, culling etc. This stage allows access to the vertices in the primitive constructed by the earlier phases, in order to interpret them and re-emit new geometry. For example, the vertex shader and primitive assembly could output single point primitives, and the geometry shader could convert this into a set of triangles for further processing. Geometry shaders can be used for a form of tessellation, but this is considered superceded by EXT_tessellation_shader. Geometry shaders can also discard primitives.

Adjacency Primitives#

As well as the standard GL primitives, this extension adds four new primitive types: LINES_ADJACENCY, LINE_STRIP_ADJACENCY, TRIANGLES_ADJACENCY and TRIANGLE_STRIP_ADJACENCY. These new types function the same as their non-adjacency counterparts everywhere except the geometry shader. In the geometry shader, these modes allow access to neighbouring vertices for each vertex. These neighbouring vertices can be useful as control points to bound any transformations done on input geometry.

Multiple Invocations#

As well as allowing multiple outputs, geometry shaders can actually run over the same input geometry multiple times as a form of instancing - allowing the same inputs to generate multiple outputs with different properties. By default, only one invocation is executed, but multiple can be processed with the layout qualifier - “invocations = integer-constant”.

Layered Rendering#

For use cases such as stereoscopic (or other multi-view) rendering, it is often desirable to do some vertex shading only once, rather than repeating it over and over for each view. Geometry shader functionality described so far can allow this by using multiple invocations to transform geometry from different angles, but each view may need to be output to a separate render target. To handle this use case, this extension adds functionality called layered rendering, which allows framebuffers to be created with multiple layers. The geometry shader can then choose which layer its outputs will be sent to via the special gl_Layer output value.

Inputs#

Geometry shader inputs come in the form of Shader IO blocks - including the built-in inputs. Built-in inputs match the built-in vertex shader outputs, but are passed through a built-in io block: gl_in. This is to distinguish them from output values.

Note

This block does not include point size unless EXT_geometry_point_size is supported and enabled.

Each io block is actually an array of blocks, and each is either implicitly (or explicitly) sized to the number of vertices available for each primitive type (e.g. 1 for a point, 2 for a line, 3 for a triangle, etc.).

As well as the built-in block for vertex shader outputs, two additional values are provided:

  • gl_PrimitiveIDIn, which is a counter that describes how many primitives have been processed by the shader during this render.

  • gl_InvocationID, which indicates how many times this shader has been invoked using Multiple Invocations.

Outputs#

Geometry shader outputs are the same as inputs, except for the built-in values, which are not part of an io block - instead they are free variables in the same way as they are in a vertex shader. gl_PrimitiveID is also provided as a modifiable output value that is passed on towards the fragment shader.

Example#

// Create a Geometry Shader
GLuint geometryShader = glCreateShader(GL_GEOMETRY_SHADER_EXT);

Example#

#extension GL_EXT_geometry_shader : require
#extension GL_EXT_shader_io_blocks : require
// Take in point primitives.
layout(points) in;
// Output up to 1 line primitive - needs at least two vertices (one line).
layout(lines, max_vertices = 2) out;
void main()
{
    // Emit the first vertex for the output primitive - below the original point
    gl_Position = gl_in[0].gl_Position + vec4(0.0,-0.1, 0.0, 0.0);
    EmitVertex();
    // Emit the second vertex for the output primitive - above the original point
    gl_Position = gl_in[0].gl_Position + vec4( 0.0, 0.1, 0.0, 0.0);
    EmitVertex();
    // End the (line) primitive
    EndPrimitive();
}