Well, it’s been awhile since I meandered on over to Tom Nyuden’s Delphi3D OpenGL tutorial page. A few months ago a demo was posted that carried Tom’s usual statement that the application would likely only work with NV 68xx + graphics accelerators.
The ARB made a decision to choose GLSL over Cg as the supported high level shading language, beginning with the introduction of ARB_vertex_shader and ARB_fragment_shader OpenGL API extensions. When NVIDIA released a compiler, it did so with a quite interesting set ofrelease notes. This was done August 30th, 2004. Well over a year ago, NVIDIA admitted that they did not supply a conformant compiler and they’ve yet to do so. Thankfully, NVIDIA’s compiler does consume valid GLSL code, it is simply relaxed (consuming much of the Cg grammar as well). 3Dlabs came out with an open source tool called GLSL Validate that enables developers to ensure their code is portable. It simply is a specification conformant compiler front end that can run on any computer, even one without an OpenGL enabled graphics card! For reasons unbenownst to myself and much of the OpenGL community, the tutorials found on Delphi3D have contained non-portable, non-compliant, syntactically incorrect OpenGL Shading Language shaders. They will only run on NVIDIA hardware because only the NVIDIA compiler accepts malformed code such as that contained within the demos. My first attempt to correct this with the developer at Delphi3D resulted in him shutting down the thread I posted in and not responding to any of my emails or forum postings. One thing I will say with certainty is that the demos on Delphi3D are awesome! It is a shame that they are being promoted as GLSL demos and are ill formed! This posting will go over one of the shaders in his most recent demo, HDR rendering. (High Dynamic Range) The shader that fails to compile on conformant hardware is the f_blur.glsl fragment shader. The OpenGL Shading Language Specification states in section 4.1.9 There is no mechanism for initializing arrays at declaration time from within a shader. Taking a look at line 6 of the shader, we see the following:
. . .
const float weights[] = {
1.0000,
0.9394,
0.7788,
0.5697,
0.3678,
0.2096,
0.1053,
0.0467,
0.0183,
};
. . .
Clearly, this array is being initialized. Since according to the specification there is no mechanism to do this, the parser should not consume this code. A compile time error should be generated. If the desire is for these to be const floats, this should be written as follows:
. . .
const float weight0 = 1.000;
const float weight1 = 0.9394;
const float weight2 = 0.7788;
. . .
In the shader’s main loop an array can be declared and the values inserted into the array.
. . .
float weights[9];
weights[0] = weight0;
weights[1] = weight1;
. . .
Next, there is a texture lookup that indexes into a two dimensional texture, using a vec4 to index into the two dimensional texture, whereas the spec requires a vec2.
//as written
. . .
vec4 color = texture2D(t_hdrimage, gl_TexCoord[0]) * weights[0];
. . .
//corrected
. . .
vec4 color = texture2D(t_hdrimage, gl_TexCoord[0].xy) * weights[0];
. . .
Next, the shader attempts to autopromote an integer to a float. This also is explicitly disallowed in the language specification.
//as written
. . .
for (int i = 1; i < = samples; i++)
{
offset = blur_offset * i;
. . .
//corrected
. . .
for (int i = 1; i< =samples; i++)
{
offset = blur_offset * float(i);
. . .
Last but not least, two more texture lookups are attempted using a 4 dimensional vector to index into a 2 dimensional texture.
//as written
vec4 tc;
vec4 offset;
. . .
tc = gl_TexCoord[0] + offset;
color += texture2D(t_hdrimage, tc) * weights[i];
. . .
tc = gl_TexCoord[0] - offset;
color += texture2D(t_hdrimage, tc) * weights[i];
. . .
//corrected
vec4 tc;
vec4 offset;
. . .
tc = gl_TexCoord[0] + offset;
color += texture2D(t_hdrimage, tc.st) * weights[i];
. . .
tc = gl_TexCoord[0] - offset;
color += texture2D(t_hdrimage, tc.st) * weights[i];
. . .
As you can see from the infolog below, we’ve started with a shader that would not compile and managed to quickly fix it up into a portable GLSL shader!
Parsing fragment shader ‘f_blur.glsl’….
Failure.ERROR: 0:33: ‘texture2D’ : no matching overloaded function found
ERROR: 0:33: ‘=’ : cannot convert from ‘float’ to ‘4-component vector of float’
ERROR: 0:42: ‘*’ : wrong operand types no operation ‘*’ exists that takes a left-hand operand of type ‘uniform 4-component vector of float’ and a right operand of type ‘int’ (or there is no acceptable conversion)
ERROR: 0:46: ‘texture2D’ : no matching overloaded function found
ERROR: 0:50: ‘texture2D’ : no matching overloaded function found
ERROR: 5 compilation errors. No code generated.Parsing fragment shader ‘f_blur.glsl’….
Failure.ERROR: 0:42: ‘*’ : wrong operand types no operation ‘*’ exists that takes a left-hand operand of type ‘uniform 4-component vector of float’ and a right operand of type ‘int’ (or there is no acceptable conversion)
ERROR: 0:46: ‘texture2D’ : no matching overloaded function found
ERROR: 0:50: ‘texture2D’ : no matching overloaded function found
ERROR: 3 compilation errors. No code generated.Parsing fragment shader ‘f_blur.glsl’….
Failure.ERROR: 0:46: ‘texture2D’ : no matching overloaded function found
ERROR: 0:50: ‘texture2D’ : no matching overloaded function found
ERROR: 2 compilation errors. No code generated.Parsing fragment shader ‘f_blur.glsl’….
Success.
In closing, I am extremely appreciative of the contributions Tom has made to the OpenGL community with his site, Delphi3D. I hope that he continues to release demos, and that given this post is able to appreciate the importance and simplicity of providing aspiring developers of programmable graphics well formed portable code to learn from.
I must also say that this posting - along with all other posts done on this site, are done on my own time and are of my own opinion.

