GLSL

Shader System

GLSL cannot be precompiled, which makes OpenGL the only SpeedTree-supported graphics API where precompiled shaders cannot be used. The biggest impact with this is that the SpeedTree Compiler can generate a pretty large bank of shaders for a given forest. As such, it may much longer for OpenGL to load a bank of shaders (e.g. many seconds), than for a platform that supports precompiled shaders (e.g. just a couple hundred milliseconds). ATI OpenGL drivers, especially, are particularly slow when compiling shaders that use Uniform Buffer Objects, which SpeedTree employs to support instancing under OpenGL.

Note: The SpeedTree OpenGL renderer employs a mechanism to save off the compiled shader using a platform-specific format. This will result in much faster shader loading on subsequent runs, but the generated files are videocard vendor-specific.

Another important area where GLSL differs from HLSL/Cg-type syntax is the ability to assign which constant registers the uniform constants will reside in (this is in fact possible, but requires newer OpenGL extensions). The SDK relies on each shader having the uniform shader constants residing in the same registers so that they don't have to be reassigned each time a new shader is bound (imagine having to upload the projection/view matrix and many other uniforms each time one of possibly dozens of shaders are bound each frame; it's a waste). To get around this restriction, the SpeedTree shader templates allocate one large uniform constant array and assign indices for each of the global variables (see the OpenGL section of ShaderConstants.h for details of how this is implemented). The OpenGL renderer will perform a “sanity check” that this unform array is assigned to register zero for every shader, else the approach will not work.

Two other operations are necessary for GLSL to behave similarly to its HLSL counterpart to be portable in the SpeedTree SDK:

  1. The vertex shader incoming very attributes must be manually bound. When a vertex attribute is declared, an OpenGL driver's GLSL compiler is free to bind it to any of the attribute slots 0 to 15, and consistency between compilers is not required. To gain reliable consistency, the SpeedTree SDK will lookup the vertex attributes by sequenial name (e.g. in_vSlot0, in_vSlot1, etc.), and assign them to attribute locations 0, 1, etc. respectively. This is handled in BindVertexAttributes() in Shaders.inl of the OpenGL renderer library.
  1. 2 Textures must be bound to their samplers, and bound consistently across all shaders (more on what that means here: http://www.opengl.org/wiki/GLSL_Sampler#Binding_textures_to_samplers). This is handled in BindTextureSamplers() in Shaders.inl of the OpenGL renderer library, and note that it will need to be updated if more samplers/textures are added to the system.