I experimented and got the result that subroutine can not call another subroutine in a single shader. Take the example I posted below.
In phong mode, the following instruction failed the program linking.
vec3 diffuse = diffuseOnly(position, norm);
===
#version 400
subroutine vec3 shadeModelType( vec4 position, vec3 normal);
subroutine uniform shadeModelType shadeModel;
layout (location = 0) in vec3 VertexPosition;
layout (location = 1) in vec3 VertexNormal;
layout (location = 2) in int VertexColorIndex;
out vec3 LightIntensity;
struct LightInfo {
vec4 Position; // Light position in eye coords.
vec3 La; // Ambient light intensity
vec3 Ld; // Diffuse light intensity
vec3 Ls; // Specular light intensity
};
uniform LightInfo Light;
struct MaterialInfo {
vec3 Ka; // Ambient reflectivity
vec3 Kd; // Diffuse reflectivity
vec3 Ks; // Specular reflectivity
float Shininess; // Specular shininess factor
};
uniform MaterialInfo Material;
uniform mat4 ModelViewMatrix;
uniform mat3 NormalMatrix;
uniform mat4 ProjectionMatrix;
uniform mat4 MVP;
void getEyeSpace( out vec3 norm, out vec4 position )
{
norm = normalize( NormalMatrix * VertexNormal);
position = ModelViewMatrix * vec4(VertexPosition,1.0);
}
subroutine( shadeModelType )
vec3 phongModel( vec4 position, vec3 norm )
{
vec3 s = normalize(vec3(Light.Position - position));
vec3 v = normalize(-position.xyz);
vec3 r = reflect( -s, norm );
vec3 ambient = Light.La * Material.Ka;
float sDotN = max( dot(s,norm), 0.0 );
vec3 diffuse = Light.Ld * Material.Kd * sDotN;//does work.
//vec3 diffuse = diffuseOnly(position, norm); //does not work.
vec3 spec = vec3(0.0);
if( sDotN > 0.0 )
spec = Light.Ls * Material.Ks *
pow( max( dot(r,v), 0.0 ), Material.Shininess );
return ambient + diffuse + spec;
}
subroutine( shadeModelType )
vec3 diffuseOnly( vec4 position, vec3 norm )
{
vec3 s = normalize( vec3(Light.Position - position) );
vec3 materialCatelogue;
switch(int(mod(VertexColorIndex, 9)))
{
case 0:
default:
materialCatelogue = Material.Kd;
break;
case 1:
materialCatelogue = vec3(1.0, 0.0, 0.0);
break;
case 2:
materialCatelogue = vec3(0.0, 1.0, 0.0);
break;
case 3:
materialCatelogue = vec3(0.0, 0.0, 1.0);
break;
case 4:
materialCatelogue = vec3(1.0, 1.0, 0.0);
break;
case 5:
materialCatelogue = vec3(1.0, 0.0, 1.0);
break;
case 6:
materialCatelogue = vec3(0.0, 1.0, 1.0);
break;
case 7:
materialCatelogue = vec3(1.0, 1.0, 1.0);
break;
case 8:
materialCatelogue = vec3(0.0, 0.0, 0.0);
break;
}
return Light.Ld * materialCatelogue * max( dot(s, norm), 0.0 );
}
subroutine( shadeModelType )
vec3 ambientOnly( vec4 position, vec3 norm )
{
return Material.Ka;
}
void main()
{
vec3 eyeNorm;
vec4 eyePosition;
// Get the position and normal in eye space
getEyeSpace(eyeNorm, eyePosition);
// Evaluate the shading equation. This will call one of
// the functions: diffuseOnly or phongModel.
LightIntensity = shadeModel( eyePosition, eyeNorm );
gl_Position = MVP * vec4(VertexPosition,1.0);
}