I am binding all of my fragment out variables iteratively for my shader program before linking via…

```
glBindFragDataLocation()
```

To test to make sure they were bound correctly, after linking, I then call iteratively…

```
glGetFragDataLocation
```

If it returns -1, then we know the fragment out variable wasn’t bound.

My problem is that neither ZMapOut[0] or ZMapOut[1] out variable reports having bound successfully, based on the above method.

I reasoned that either this is a bug in the driver (unlikely), the driver compiler optimized out those variables because it determined they weren’t used (but my shader appears to write to them unconditionally), or lastly, glGetFragDataLocation might be unreliable in certain circumstances.

Vertex shader:

```
// We want at least GLSL 1.50...
#version 150
// Input variables...
// Grid location...
in vec2 GridLocation;
// Uniform variables...
// Dimensions...
uniform uint Width;
uniform uint Height;
// Variables for the fragment shader, none of which need be interpolated...
// Normalized location cooresponding to grid location...
out vec2 NormalizedLocation;
// Texture location cooresponding to grid location...
out vec2 TextureLocation;
// Entry point...
void main()
{
// Calculate texture location which has components in [0, 1] range...
TextureLocation = GridLocation / vec2(Width, Height);
// Calculate normalized location which has components in [-1, 1] range...
NormalizedLocation = TextureLocation * vec2(2.0, 2.0) - vec2(1.0, 1.0);
// Generate a fragment...
gl_Position = vec4(NormalizedLocation, 0.0, 1.0);
}
```

Fragment shader:

```
// Preprocessor directives...
// Select language version...
#version 150
// Useful for debugging...
#pragma optimize(off)
#pragma debug(on)
// Input variables...
// Normalized location cooresponding to grid location...
in vec2 NormalizedLocation;
// Texture location cooresponding to grid location...
in vec2 TextureLocation;
// Uniform variables...
// Dimensions...
uniform uint Width;
uniform uint Height;
// Source buffer index...
uniform int SourceBufferIndex;
// Grid spacing between vertices...
uniform float DistanceBetweenVertices;
// Pre-computed equation constants...
uniform float CachedConstant1;
uniform float CachedConstant2;
uniform float CachedConstant3;
// Z-displacement maps...
uniform sampler2D ZMapIn[2];
// Output variables...
// Z-displacement output buffers...
out float ZMapOut[2];
// Normal...
out vec3 Normal;
// Tangent...
out vec3 Tangent;
// Take a grid location and transform to a normalized texture coordinate...
vec2 GridToTexture(const uvec2 Location)
{
// Transform to [0..1] and return it...
return (Location / vec2(Width, Height));
}
// Take coordinate normalized in [-1..1] and transform to [0..Width or Height]...
uvec2 NormalizedPointToGrid(const vec2 Normalized)
{
// Transform and return it... p = (d/2)(p'+1)
return uvec2((vec2(Width, Height) * vec2(0.5, 0.5)) * (Normalized + vec2(1.0, 1.0)));
}
// Transform coordinate in [-1..1] to [0..1]
vec2 NormalizedPointToTexture(const vec2 Normalized)
{
// Transform normalized form to texture coordinate... p_t = (p' + <1,1>) / 2
return (Normalized + vec2(1.0, 1.0)) * vec2(0.5, 0.5);
}
// Entry point...
void main()
{
// Get location on grid...
uvec2 GridLocation = NormalizedPointToGrid(NormalizedLocation);
// We assume the outer edge of fluid surface is fixed. This also makes
// querying neighbours easier since we can assume there always will be
// exactly eight all around it after this, though we don't affect the
// diagonal neighbours...
if(GridLocation.x == 0u || GridLocation.x == (Width - 1u) ||
GridLocation.y == 0u || GridLocation.y == (Height - 1u))
discard;
// The previous buffer's index...
int PreviousBufferIndex = int(!bool(SourceBufferIndex));
// Lookup displacement of current location...
float CurrentZ = texture(ZMapIn[SourceBufferIndex], TextureLocation).r;
// Lookup displacement current location's neighbours...
float AboveCurrentZ = texture(ZMapIn[SourceBufferIndex], GridToTexture(GridLocation + uvec2( 0, 1))).r;
float BelowCurrentZ = texture(ZMapIn[SourceBufferIndex], GridToTexture(GridLocation + uvec2( 0, -1))).r;
float LeftCurrentZ = texture(ZMapIn[SourceBufferIndex], GridToTexture(GridLocation + uvec2(-1, 0))).r;
float RightCurrentZ = texture(ZMapIn[SourceBufferIndex], GridToTexture(GridLocation + uvec2( 1, 0))).r;
// Lookup displacement of last passes displacement at current location...
float PreviousZ = texture(ZMapIn[PreviousBufferIndex], TextureLocation).r;
// Update previous buffer's displacement here using equation 12.25, p.335,
// of Mathematics for 3D Game Programming and Computer Graphics. */
PreviousZ = CachedConstant1 * CurrentZ + /* first term */
CachedConstant2 * PreviousZ + /* second term */
CachedConstant3 * (RightCurrentZ + LeftCurrentZ + /* third term */
AboveCurrentZ + BelowCurrentZ);
// Write out displacement to destination buffer...
ZMapOut[PreviousBufferIndex] = PreviousZ;
}
```

I posted the vertex shader as well, just in case the problem originated in there somewhere.

Kip