In this lab, you will be introduced to the GLSL (OpenGL Shader Language) and use it for computational purposes.
OpenGL Shader Language has a central role in computer graphics, as a cornerstone of the leading graphics library OpenGL. With recent editions of the library, more and more tasks are carried out in shaders. As shaders have become increasingly capable, these tasks have expanded into realms outside the most obvious graphics tasks. Although CUDA and OpenCL provide more control over shared memory, scattered writes and synchronizations, and hides the graphics heritage of GLSL, GLSL still is very important.
In this lab, we will spend some time on using GLSL for graphics, but focus on its use for computing, first by applying filters to images, and then for general computing on non-image data.
A brief introduction to the GLSL language is available here.
The lab is examined though a simple lab report. You should package your code (without data files or object files, please), plus comments about the result as noted below. Comments should be in a plain text file or in the body of your mail. E-mail to Ingemar.
Goal: To get comfortable with GLSL.
Non-mandatory introduction! This is for those of you who have not used GLSL before or need to refresh your memory a bit.
We will start with "conventional" shader programming for graphics. We skip lighting calculations altogether here and focus on texturing and computation. However, this first part is a standard one just to get started.
You start from code where some textures have been loaded for you. teapotshader.zip. A makefile is included.
Your task is to combine all three textures in some interesting way. You are encouraged to be creative. Note that textures can be used for other things than image data.
QUESTION: How did you combine the textures?
Goal: To make a computationally more challenging shader with GLSL.
Let us do something of a more computational nature. "Ingemar's psychedelic teapot" is provided for you. Download it here. A makefile is included.
Modify this demo to produce a fractal image on the teapot instead. We suggest that you produce a Mandelbrot or Julia fractal. Use the texture coordinates as input to the fractal generator.
Note that shaders do not allow recursive functions. Thus, your fractal code must be iterative, and with a constant loop number.
QUESTION: How did you replace the recursion?
Goal: To learn how to perform filtering and multi-pass computing in GLSL.
Now we switch to the generic GPGPU style, with a single rectange over the entire screen. You will be using FBOs for rendering to texture. The lab shell is here:
imagefilter-to.zip Older version.
The heart of the code is the FBO handling code, which makes ping-ponging easy. A number of FBOs are created, with the input image being loaded into fbo1. Using the call useFBO, you can set any fbo as output (first argument) or input (second two). You primarily work in the shaders and in the display() function, plus in main() for adding new shaders.
a) 2D convolution
We have "made the bed" for you fairly well in the lab shell with a small filter kernel. Expand it to a 7x7 low-pass filter (any kind you like, preferrably separable; I suggest an approximation to gaussian).
b) Separable filter kernels
Now, you must use at least two passes, applying a separable filter kernel to the image. Construct one 7x1 and one 1x7 kernel. The result should be similar to the one in 3a.
c) Performace test
Above, you made two similar or equivalent filters computed in two different ways.
Run a performance comparison on a) and b). Loop the computation sufficiently to get a stable measure. Use glFinish() to make sure that the computations finish properly. Run several tests in succession, so any startup transients don't affect the total.
You can use milli.c for a microsecond timer, as is already done in the imagefilter.c main program.
QUESTION: Do you have to make boundary checks for filters in GLSL? If not, why not?
QUESTION: What running time did you get from the two cases?
Finally, we will turn to problems of a purely non-image nature. We will work on 1-dimensional arrays of numbers.
a) Simple floating-point calculations
The lab shell (process-array) uploads an array of floats to the GPU which takes the square root of all items. Experiment with data sizes and computations and inspect the running time.
Old lab files (not recommended but provided as backup):
QUESTION: What running time did for GPU vs CPU? With or without downloading the result to the CPU?
You will now work on a given array of floating-point numbers, the fix-array program in the lab shell. The lab shell is similar to the previous one but includes some simple re-arranging tricks.
You should perform one of the following tasks:
QUESTION: What algorithm did you implement?