Simple Introduction to OpenGL 4 Shader Subroutines

OpenGL 4 shader subroutines tutorial

Article index:

1 – Overview

Shader subroutines are a feature introduced in OpenGL 4.0 via this extension: GL_ARB_shader_subroutine:

This extension adds support to shaders for “indirect subroutine calls”, where a single shader can include many subroutines and dynamically select through the API which subroutine is called from each call site. Switching subroutines dynamically in this fashion can avoid the cost of recompiling and managing multiple shaders, while still retaining most of the performance of specialized shaders.


Subroutines are a nice alternative to conditional tests or shader swaps and allows to manage shader combinations. With subroutines, you can have a single GPU program (an übershader) that can perform several tasks instead of a collection of specialised GPU programs. Subroutines are easy to setup and use.

To illustrate this article, I coded with GLSL Hacker a small demo that renders a PQ torus knot in three colors: red, blue and yellow. Each color is managed by a subroutine. Just press on the SPACE key to change the subroutine. The demo is available in the host_api/gl-400-arb-shader-subroutine/ folder of the code sample pack.

You can play with the demo under Windows, Mac OS X 10.9 and Linux. An OpenGL 4 capable card is required (NVIDIA GeForce GTX 400+, AMD Radeon HD 5000+, Intel HD Graphics 4000+). Start GLSL Hacker and load (or drag n drop under Win/OSX) the demo file in GLSL Hacker main window, that’s all.

OpenGL 4 Shader Subroutines

2 – Shader Subroutines Details

Let’s start with the GLSL program. Here is the fragment shader where subroutines are used:

#version 400

out vec4 FragColor;

subroutine vec4 color_t();

subroutine uniform color_t Color;

subroutine(color_t)
vec4 ColorRed()
{
  return vec4(1, 0, 0, 1);
}

subroutine(color_t)
vec4 ColorBlue()
{
  return vec4(0, 0.4, 1, 1);
}

subroutine(color_t)
vec4 ColorYellow()
{
  return vec4(1, 1, 0, 1);
}

void main()
{
  FragColor = Color();
}

The first thing to do is to declare the subroutine prototype:

subroutine vec4 color_t();

Next you have to declare a subroutine uniform called Color. Color is a kind of pointer function and you will call it to draw the torus knot with FragColor = Color();

subroutine uniform color_t Color;

Now the real subroutines. Each subroutine must follow the prototype declared previously. To tell to the GLSL compiler that a function is a subroutine, just add the subroutine qualifier before the function:

subroutine(color_t)
vec4 ColorRed()
{
  return vec4(1, 0, 0, 1);
}

Now ColorRed() is a subroutine. Same thing for ColorBlue() and ColorYellow().

Last thing, call the subroutine:

void main()
{
  FragColor = Color();
}

Easy isn’t it? Now let’ see how intialize the subroutines in the OpenGL side. The OpenGL specification defines several functions for subroutines. In our case, only two are interesting: glGetSubroutineIndex() and glUniformSubroutinesuiv().

Each subroutine has an index and the number of indices is limited. You can retrieve the max number of subroutines using GL_MAX_SUBROUTINES:

GLint n = 0;
glGetIntegerv(GL_MAX_SUBROUTINES, &n);

On a GeForce GTX 660, GL_MAX_SUBROUTINES gives 1024.

The index of a subroutine can be retrieved using glGetSubroutineIndex(). Here is how to get the index of the ColorRed() subroutine:

GLuint color_red_index = glGetSubroutineIndex(program, GL_FRAGMENT_SHADER, "ColorRed");

Once you have the indices of all subroutines, you can select one particular subroutine using its index. Here is how to select and use the ColorRed() subroutine:

glUseProgram(program);
glUniformSubroutinesuiv(GL_FRAGMENT_SHADER, 1, &color_red_index);
...
drawTorusKnot();

In the GLSL Hacker demo, the selection of the ColorRed() subroutine is done by:

gh_gpu_program.set_uniform_subroutine(gpu_prog, GPU_SHADER_PIXEL, "Color", "ColorRed")

OpenGL 4 Shader Subroutines - Mac OS X

3 – References

Original article (in french):
Petite Introduction aux Shader Subroutines d’OpenGL 4.0

Other references:

3 thoughts on “Simple Introduction to OpenGL 4 Shader Subroutines”

  1. AngryBaguette

    With a custom UberShader implementation it’s generally interesting to sort our object by UberShader specialization in order to minimize context switching cost.

    With the subroutine technique is it necessary to sort objects by subroutine uniform ‘value’ in order to maximize performance?

Comments are closed.