GPU Programming with GLSL

CS 482 Lecture, Dr. Lawlor

GLSL is one of the standard languages today for describing the code used to drawing pixel to the screen on modern graphics cards.

Non-Programmable Shaders

Back in the day (2000 AD), graphics cards had finally managed to compute all of OpenGL in hardware.  They had hardware projection matrices, hardware clipping, hardware transform-and-lighting, hardware texturing, and so on.  Folks were thrilled, because glQuake looked amazing and ran great.

There's a problem with hardware, though.  It's hard to change.

And no two programmers ever want to do, say, bump mapping exactly the same way.  Some want shadows.  Some want bump-and-reflect.  Some want bump-and-light.  Some want light-and-bump.  nVidia and ATI were going crazy trying to support every developer's crazy desires in hardware.  For example, my ATI card still supports these OpenGL extensions, just for variations on bump/environment mapping:
GL_EXT_texture_env_add, GL_ARB_texture_env_add, GL_ARB_texture_env_combine, 
GL_ARB_texture_env_crossbar, GL_ARB_texture_env_dot3, GL_ARB_texture_mirrored_repeat,
GL_ATI_envmap_bumpmap, GL_ATI_texture_env_combine3, GL_ATIX_texture_env_combine3,
GL_ATI_texture_mirror_once, GL_NV_texgen_reflection, GL_SGI_color_matrix, ...
This was no good.  Programmers had good ideas they couldn't get into hardware.  Programmers were frustrated trying to understand what the heck the hardware guys had created.  Hardware folks were tearing their hair out trying to support "just one more feature" with limited hardware.

The solution to the "too many shading methods to support in hardware" problem is just to support every possible shading method in hardware.  The easy way to do this is just make the shading hardware programmable.  

So, they did. 

Programmable Shaders are Very Simple in Practice

The graphics hardware now lets you do anything you want to incoming vertices and fragments.  Your "vertex shader" code literally gets control and figures out where an incoming glVertex should be shown onscreen, on newfangled drivers the "geometry shader" can then split or cull the vertices in a triangle, and finally your "fragment shader" figures out what color each pixel should be.

Here's what this looks like in C++.  The following is C++ code, relying on the "makeProgramObject" shader-handling function listed below.  The vertex and fragment shaders are the strings in the middle.  These are very simple shaders, but they can get arbitrarily complicated.
void my_display(void) {
glClearColor(0,0,0,0); /* erase screen to black */
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

/* Set up programmable shaders */
static GLhandleARB prog=makeProgramObject(
"//GLSL Vertex shader\n"
"void main(void) {\n"
" gl_Position=gl_ModelViewProjectionMatrix * gl_Vertex;\n"
"}\n"
,
"//GLSL Fragment (pixel) shader\n"
"void main(void) {\n"
" gl_FragColor=vec4(1,0,0,1); /* that is, all pixels are red. */\n"
"}\n"
);
glUseProgramObjectARB(prog);

... glBegin, glVertex, etc. Ordinary drawing here runs with the above shaders! ...

glutSwapBuffers(); /* as usual... */
}
A few meta-observations first:
The stuff in strings is all "OpenGL Shading Language" (GLSL) code.  Just think of GLSL as plain old C++ with a nice set of 3D vector classes, and you're pretty darn close (I often use osl/vec4.h to copy and paste code between GLSL and C++!).
Data types in GLSL work exactly like in C/C++/Java/C#.  There are some beautiful builtin datatypes, though:
Bottom line: programmable shaders really are pretty easy to use.

GLSL for Simulation

There are many opportunities to use GLSL in simulations.  First, we can get much higher performance by running our simulation code in a pixel shader, which allows all the pixels to execute in parallel.  The downside is we need to make all the inputs and outputs shader friendly, which we'll be working on this week.

Second, we can provide better display of our simulation's outputs, by including per-pixel information such as the camera direction, lighting, contrast, etc.

Further Info

Try it!  Here's my simple PixAnvil fragment shader demo.

See also the GLSL cheat sheet (especially for builtin variables).

The official GLSL Language Specification isn't too bad--chapter 7 lists the builtin variables, chapter 8 the builtin functions.  OpenGL ES / GL 3.0 is similar, but they deprecated a bunch of the builtin variables from fixed-function GL.